diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-10-05 18:20:55 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-10-05 18:20:55 +0000 |
commit | d32030ae51012a5bd86f8d0db70ee670114aae1e (patch) | |
tree | 0a4b65f9ca6da9bf2d7a2f41f4d115cce477dd26 /kaffeine/src/input | |
parent | c1aed14da1f321034f34246af4410993cd0e8912 (diff) | |
download | kaffeine-d32030ae51012a5bd86f8d0db70ee670114aae1e.tar.gz kaffeine-d32030ae51012a5bd86f8d0db70ee670114aae1e.zip |
Updated Kaffeine to latest upstream version
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/kaffeine@1182813 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kaffeine/src/input')
200 files changed, 16876 insertions, 7763 deletions
diff --git a/kaffeine/src/input/disc/Makefile.am b/kaffeine/src/input/disc/Makefile.am index b9827cc..fe91515 100644 --- a/kaffeine/src/input/disc/Makefile.am +++ b/kaffeine/src/input/disc/Makefile.am @@ -28,7 +28,7 @@ libkaffeinedisc_la_LDFLAGS = $(KDE_RPATH) \ libkaffeinedisc_la_LIBADD = $(top_builddir)/kaffeine/src/input/libkaffeineinput.la \ $(top_builddir)/kaffeine/src/player-parts/kaffeine-part/libkaffeinepart.la \ $(top_builddir)/kaffeine/src/input/disc/plugins/libkaffeineaudioencoder.la \ - -lcdda_interface -lcdda_paranoia + -lcdio_cdda -lcdio_paranoia # this is where the XML-GUI resource file goes shellrcdir = $(kde_datadir)/kaffeine diff --git a/kaffeine/src/input/disc/paranoia.cpp b/kaffeine/src/input/disc/paranoia.cpp index 60e2092..fad1729 100644 --- a/kaffeine/src/input/disc/paranoia.cpp +++ b/kaffeine/src/input/disc/paranoia.cpp @@ -120,7 +120,7 @@ KiloConfig::~KiloConfig() { } -void paranoiaCallback( long, int ) +void paranoiaCallback( long int, paranoia_cb_mode_t ) { } @@ -396,7 +396,7 @@ void Paranoia::run() curpos = currentSector; endpos = endOfTrack; if ( normalize ) { - len = CD_FRAMESIZE_RAW; + len = CDIO_CD_FRAMESIZE_RAW; fn.open( IO_ReadWrite | IO_Truncate ); do { buf = paranoia_read_limited( p, paranoiaCallback, 3 ); @@ -419,7 +419,7 @@ void Paranoia::run() while ( curpos<endpos && len!=0 ); factor = 32767.0/max; - buf = new signed short[CD_FRAMESIZE_RAW]; + buf = new signed short[CDIO_CD_FRAMESIZE_RAW]; fn.at( 0 ); f.open( IO_ReadWrite | IO_Truncate ); currentEncoder->start( encodingList[i].remove(0,3), encodingList[0], encodingList[1], encodingList[i].left(2) ); @@ -428,7 +428,7 @@ void Paranoia::run() f.writeBlock( encoded, len ); do { - len = fn.readBlock( (char*)buf, CD_FRAMESIZE_RAW ); + len = fn.readBlock( (char*)buf, CDIO_CD_FRAMESIZE_RAW ); if ( len>0 ) { if ( max<32760 ) for ( n=0; n<len/2; ++n ) @@ -455,7 +455,7 @@ void Paranoia::run() encoded = currentEncoder->getHeader( len ); if ( encoded ) f.writeBlock( encoded, len ); - len = CD_FRAMESIZE_RAW; + len = CDIO_CD_FRAMESIZE_RAW; do { buf = paranoia_read_limited( p, paranoiaCallback, 3 ); if ( Q_BYTE_ORDER == Q_BIG_ENDIAN ) { @@ -514,7 +514,7 @@ QString Paranoia::trackSize( int t ) QString s, c; long total; - total = CD_FRAMESIZE_RAW * (cdda_track_lastsector( d, t+1 )-cdda_track_firstsector( d, t+1 ) ); + total = CDIO_CD_FRAMESIZE_RAW * (cdda_track_lastsector( d, t+1 )-cdda_track_firstsector( d, t+1 ) ); if ( total>(1048576 ) ) s = c.setNum(total/1048576.0, 'f', 2)+" "+i18n("MB"); else if ( total>1024 ) s = c.setNum(total/1024.0, 'f', 2)+" "+i18n("KB"); else s = c.setNum(total*1.0, 'f', 2)+" "+i18n("Bytes"); @@ -532,8 +532,8 @@ QString Paranoia::trackTime( int t ) long total, time; int m, s; - if ( t<0 ) total = CD_FRAMESIZE_RAW * (cdda_disc_lastsector( d )-cdda_disc_firstsector( d ) ); - else total = CD_FRAMESIZE_RAW * (cdda_track_lastsector( d, t+1 )-cdda_track_firstsector( d, t+1 ) ); + if ( t<0 ) total = CDIO_CD_FRAMESIZE_RAW * (cdda_disc_lastsector( d )-cdda_disc_firstsector( d ) ); + else total = CDIO_CD_FRAMESIZE_RAW * (cdda_track_lastsector( d, t+1 )-cdda_track_firstsector( d, t+1 ) ); time = (8 * total) / (44100 * 2 * 16); m = time/60; s = time%60; diff --git a/kaffeine/src/input/disc/paranoia.h b/kaffeine/src/input/disc/paranoia.h index 4864b06..ae269d4 100644 --- a/kaffeine/src/input/disc/paranoia.h +++ b/kaffeine/src/input/disc/paranoia.h @@ -32,8 +32,8 @@ extern "C" { -#include <cdda_interface.h> -#include <cdda_paranoia.h> +#include <cdio/cdda.h> +#include <cdio/paranoia.h> } class KiloConfig : public ParanoiaSettings @@ -91,8 +91,8 @@ private: bool setPath( QString &path, const QString &artist, const QString &album ); long nTracks; - cdrom_drive *d; - cdrom_paranoia *p; + cdrom_drive_t *d; + cdrom_paranoia_t *p; long currentSector, endOfTrack; bool isRunning; QStringList encodingList; diff --git a/kaffeine/src/input/disc/plugins/oggvorbis/Makefile.am b/kaffeine/src/input/disc/plugins/oggvorbis/Makefile.am index 91b63c1..7ac8f45 100644 --- a/kaffeine/src/input/disc/plugins/oggvorbis/Makefile.am +++ b/kaffeine/src/input/disc/plugins/oggvorbis/Makefile.am @@ -10,7 +10,7 @@ noinst_HEADERS = koggenc.h libkaffeineoggvorbis_la_SOURCES = koggenc.cpp oggconfig.ui libkaffeineoggvorbis_la_LIBADD = ../libkaffeineaudioencoder.la $(LIB_OGGVORBIS) -libkaffeineoggvorbis_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) $(LIB_QT) -lDCOP $(KDE_PLUGIN) $(LIB_KPARTS) $(LIB_KDECORE) $(LIB_KDEUI) $(LIB_KIO) -avoid-version -no-undefined +libkaffeineoggvorbis_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -avoid-version -no-undefined # this is where the desktop file will go partdesktopdir = $(kde_servicesdir) diff --git a/kaffeine/src/input/dvb/Makefile.am b/kaffeine/src/input/dvb/Makefile.am index 7b6c866..d5b1035 100644 --- a/kaffeine/src/input/dvb/Makefile.am +++ b/kaffeine/src/input/dvb/Makefile.am @@ -30,6 +30,8 @@ libkaffeinedvb_la_SOURCES = audioeditor.cpp \ dvbsection.h \ dvbsi.cpp \ dvbsi.h \ + camdialog.ui \ + cammenudialog.ui \ dvbstream.cpp \ dvbstream.h \ gdvb.h \ diff --git a/kaffeine/src/input/dvb/camdialog.ui b/kaffeine/src/input/dvb/camdialog.ui new file mode 100644 index 0000000..b1c3032 --- /dev/null +++ b/kaffeine/src/input/dvb/camdialog.ui @@ -0,0 +1,149 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>CamDialog</class> +<widget class="QDialog"> + <property name="name"> + <cstring>CamDialog</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>330</width> + <height>198</height> + </rect> + </property> + <property name="caption"> + <string>CAM settings</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel9</cstring> + </property> + <property name="text"> + <string>Maximum Concurrent Services:</string> + </property> + </widget> + <widget class="QSpinBox"> + <property name="name"> + <cstring>maxServiceSpin</cstring> + </property> + <property name="minValue"> + <number>1</number> + </property> + </widget> + </hbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox1</cstring> + </property> + <property name="title"> + <string></string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Application Type:</string> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Manufacturer Code:</string> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>textLabel4</cstring> + </property> + <property name="text"> + <string>Menu String:</string> + </property> + </widget> + <widget class="QLabel" row="2" column="1"> + <property name="name"> + <cstring>manuCodeLab</cstring> + </property> + <property name="text"> + <string>_</string> + </property> + </widget> + <widget class="QLabel" row="1" column="1"> + <property name="name"> + <cstring>appManuLab</cstring> + </property> + <property name="text"> + <string>_</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Application Manufacturer:</string> + </property> + </widget> + <widget class="QLabel" row="3" column="1"> + <property name="name"> + <cstring>menuStringLab</cstring> + </property> + <property name="text"> + <string>_</string> + </property> + </widget> + <widget class="QLabel" row="0" column="1"> + <property name="name"> + <cstring>appTypeLab</cstring> + </property> + <property name="text"> + <string>_</string> + </property> + </widget> + </grid> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>camMenuBtn</cstring> + </property> + <property name="text"> + <string>CAM Menu</string> + </property> + </widget> + </vbox> + </widget> + </grid> +</widget> +<tabstops> + <tabstop>maxServiceSpin</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kaffeine/src/input/dvb/cammenudialog.ui b/kaffeine/src/input/dvb/cammenudialog.ui new file mode 100644 index 0000000..6eebfa4 --- /dev/null +++ b/kaffeine/src/input/dvb/cammenudialog.ui @@ -0,0 +1,67 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>CamMenuDialog</class> +<widget class="QDialog"> + <property name="name"> + <cstring>CamMenuDialog</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>317</width> + <height>345</height> + </rect> + </property> + <property name="caption"> + <string>CAM Menu</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout7</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QTextBrowser"> + <property name="name"> + <cstring>menuText</cstring> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout6</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Your choice (enter to validate):</string> + </property> + </widget> + <widget class="QLineEdit"> + <property name="name"> + <cstring>inputLine</cstring> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + </grid> +</widget> +<tabstops> + <tabstop>inputLine</tabstop> + <tabstop>menuText</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kaffeine/src/input/dvb/channeldesc.cpp b/kaffeine/src/input/dvb/channeldesc.cpp index 5ab4acf..7d96e48 100644 --- a/kaffeine/src/input/dvb/channeldesc.cpp +++ b/kaffeine/src/input/dvb/channeldesc.cpp @@ -115,6 +115,8 @@ Transponder::Transponder() coderateH=FEC_AUTO; bandwidth=BANDWIDTH_AUTO; snr = 0; + rolloff = ROLLOFF_AUTO; + S2 = 0; } Transponder::Transponder( const Transponder &trans ) @@ -134,6 +136,8 @@ Transponder::Transponder( const Transponder &trans ) coderateL=trans.coderateL; coderateH=trans.coderateH; bandwidth=trans.bandwidth; + rolloff = trans.rolloff; + S2 = trans.S2; } bool Transponder::sameAs( Transponder *trans ) diff --git a/kaffeine/src/input/dvb/channeldesc.h b/kaffeine/src/input/dvb/channeldesc.h index f4bc1ab..ef07011 100644 --- a/kaffeine/src/input/dvb/channeldesc.h +++ b/kaffeine/src/input/dvb/channeldesc.h @@ -101,6 +101,8 @@ public: fe_code_rate_t coderateH; fe_bandwidth_t bandwidth; int snr; + fe_rolloff_t rolloff; + char S2; }; class ChannelDesc diff --git a/kaffeine/src/input/dvb/channeleditor.cpp b/kaffeine/src/input/dvb/channeleditor.cpp index 6b04fe4..18ea8ce 100644 --- a/kaffeine/src/input/dvb/channeleditor.cpp +++ b/kaffeine/src/input/dvb/channeleditor.cpp @@ -143,6 +143,9 @@ void ChannelEditor::accept() else channel->tp.pol = 'h'; channel->tp.coderateH = (fe_code_rate_t)(FEC_NONE+coderateHComb->currentItem()); channel->tp.inversion = (fe_spectral_inversion_t)(INVERSION_OFF+inversionComb->currentItem()); + channel->tp.modulation = (fe_modulation_t)(QPSK+modulationComb->currentItem()); + channel->tp.S2 = stypeComb->currentItem(); + channel->tp.rolloff = (fe_rolloff_t)(ROLLOFF_35+rolloffComb->currentItem() ); } else if ( channel->tp.type==FE_QAM ) { channel->tp.freq = freqSpin->value(); @@ -165,13 +168,7 @@ void ChannelEditor::accept() else { channel->tp.freq = freqSpin->value(); channel->tp.inversion = (fe_spectral_inversion_t)(INVERSION_OFF+inversionComb->currentItem()); - switch (modulationComb->currentItem()) { - case 0: channel->tp.modulation = QAM_64; break; - case 1: channel->tp.modulation = QAM_256; break; - case 2: channel->tp.modulation = VSB_8; break; - case 3: channel->tp.modulation = VSB_16; break; - default: channel->tp.modulation = QAM_AUTO; break; - } + channel->tp.modulation = (fe_modulation_t)(QPSK+modulationComb->currentItem()); } done( Accepted ); @@ -187,10 +184,15 @@ void ChannelEditor::initS() inversionComb->setCurrentItem( INVERSION_OFF+channel->tp.inversion ); coderateHComb->insertStringList( coderateList() ); coderateHComb->setCurrentItem( FEC_NONE+channel->tp.coderateH ); + modulationComb->insertStringList( modulationList() ); + modulationComb->setCurrentItem( QPSK+channel->tp.modulation ); + stypeComb->insertStringList( stypeList() ); + stypeComb->setCurrentItem( channel->tp.S2 ); + rolloffComb->insertStringList( rolloffList() ); + rolloffComb->setCurrentItem( ROLLOFF_35+channel->tp.rolloff ); transmissionComb->setEnabled( false ); coderateLComb->setEnabled( false ); bandwidthComb->setEnabled( false ); - modulationComb->setEnabled( false ); hierarchyComb->setEnabled( false ); guardComb->setEnabled( false ); } @@ -211,6 +213,8 @@ void ChannelEditor::initC() bandwidthComb->setEnabled( false ); hierarchyComb->setEnabled( false ); guardComb->setEnabled( false ); + stypeComb->setEnabled( false ); + rolloffComb->setEnabled( false ); } void ChannelEditor::initT() @@ -234,6 +238,8 @@ void ChannelEditor::initT() guardComb->setCurrentItem( GUARD_INTERVAL_1_32+channel->tp.guard ); srSpin->setEnabled( false ); polGroup->setEnabled( false ); + stypeComb->setEnabled( false ); + rolloffComb->setEnabled( false ); } void ChannelEditor::initA() @@ -241,14 +247,8 @@ void ChannelEditor::initA() freqSpin->setValue( channel->tp.freq ); inversionComb->insertStringList( inversionList() ); inversionComb->setCurrentItem( INVERSION_OFF+channel->tp.inversion ); - modulationComb->insertStringList( modulationListAtsc() ); - switch (channel->tp.modulation) { - case QAM_64: modulationComb->setCurrentItem(0); break; - case QAM_256: modulationComb->setCurrentItem(1); break; - case VSB_8: modulationComb->setCurrentItem(2); break; - case VSB_16: modulationComb->setCurrentItem(3); break; - default: modulationComb->setCurrentItem(4); break; - } + modulationComb->insertStringList( modulationList() ); + modulationComb->setCurrentItem( QPSK+channel->tp.modulation ); srSpin->setEnabled( false ); polGroup->setEnabled( false ); transmissionComb->setEnabled( false ); @@ -257,6 +257,8 @@ void ChannelEditor::initA() bandwidthComb->setEnabled( false ); hierarchyComb->setEnabled( false ); guardComb->setEnabled( false ); + stypeComb->setEnabled( false ); + rolloffComb->setEnabled( false ); } QStringList ChannelEditor::inversionList() @@ -271,7 +273,7 @@ QStringList ChannelEditor::coderateList() { QStringList list; - list<<"NONE"<<"1/2"<<"2/3"<<"3/4"<<"4/5"<<"5/6"<<"6/7"<<"7/8"<<"8/9"<<"AUTO"; + list<<"NONE"<<"1/2"<<"2/3"<<"3/4"<<"4/5"<<"5/6"<<"6/7"<<"7/8"<<"8/9"<<"AUTO"<<"3/5"<<"9/10"; return list; } @@ -279,15 +281,7 @@ QStringList ChannelEditor::modulationList() { QStringList list; - list<<"QPSK"<<"QAM 16"<<"QAM 32"<<"QAM 64"<<"QAM 128"<<"QAM 256"<<"AUTO"; - return list; -} - -QStringList ChannelEditor::modulationListAtsc() -{ - QStringList list; - - list<<"QAM 64"<<"QAM 256"<<"VSB 8"<<"VSB 16"<<"AUTO"; + list<<"QPSK"<<"QAM 16"<<"QAM 32"<<"QAM 64"<<"QAM 128"<<"QAM 256"<<"AUTO"<<"VSB-8"<<"VSB-16"<<"8PSK"<<"16APSK"<<"DQPSK"; return list; } @@ -323,6 +317,22 @@ QStringList ChannelEditor::guardList() return list; } +QStringList ChannelEditor::stypeList() +{ + QStringList list; + + list<<"DVB-S"<<"DVB-S2"; + return list; +} + +QStringList ChannelEditor::rolloffList() +{ + QStringList list; + + list<<"35"<<"20"<<"25"<<"AUTO"; + return list; +} + ChannelEditor::~ChannelEditor() { } diff --git a/kaffeine/src/input/dvb/channeleditor.h b/kaffeine/src/input/dvb/channeleditor.h index 6a3b3f8..586b9a3 100644 --- a/kaffeine/src/input/dvb/channeleditor.h +++ b/kaffeine/src/input/dvb/channeleditor.h @@ -53,11 +53,12 @@ private: QStringList inversionList(); QStringList coderateList(); QStringList modulationList(); - QStringList modulationListAtsc(); QStringList transmissionList(); QStringList bandwidthList(); QStringList hierarchyList(); QStringList guardList(); + QStringList stypeList(); + QStringList rolloffList(); ChannelDesc *channel; QPtrList<ChannelDesc> *chandesc; diff --git a/kaffeine/src/input/dvb/channeleditorui.ui b/kaffeine/src/input/dvb/channeleditorui.ui index 5b75f18..09bdad1 100644 --- a/kaffeine/src/input/dvb/channeleditorui.ui +++ b/kaffeine/src/input/dvb/channeleditorui.ui @@ -9,7 +9,7 @@ <x>0</x> <y>0</y> <width>477</width> - <height>533</height> + <height>541</height> </rect> </property> <property name="caption"> @@ -19,7 +19,7 @@ <property name="name"> <cstring>unnamed</cstring> </property> - <widget class="Line" row="1" column="0"> + <widget class="Line" row="0" column="1"> <property name="name"> <cstring>line2</cstring> </property> @@ -35,7 +35,7 @@ </widget> <widget class="QLayoutWidget" row="0" column="0"> <property name="name"> - <cstring>layout9</cstring> + <cstring>layout7</cstring> </property> <vbox> <property name="name"> @@ -432,22 +432,6 @@ <cstring>transmissionComb</cstring> </property> </widget> - <widget class="QLabel" row="3" column="0"> - <property name="name"> - <cstring>textLabel11</cstring> - </property> - <property name="sizePolicy"> - <sizepolicy> - <hsizetype>4</hsizetype> - <vsizetype>5</vsizetype> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Bandwidth:</string> - </property> - </widget> <widget class="QLabel" row="2" column="0"> <property name="name"> <cstring>textLabel10</cstring> @@ -480,11 +464,6 @@ <string>Transmission:</string> </property> </widget> - <widget class="QComboBox" row="3" column="1"> - <property name="name"> - <cstring>bandwidthComb</cstring> - </property> - </widget> <widget class="QComboBox" row="2" column="1"> <property name="name"> <cstring>coderateHComb</cstring> @@ -511,11 +490,6 @@ <string>FEC low:</string> </property> </widget> - <widget class="QComboBox" row="3" column="3"> - <property name="name"> - <cstring>guardComb</cstring> - </property> - </widget> <widget class="QLabel" row="3" column="2"> <property name="name"> <cstring>textLabel7</cstring> @@ -595,6 +569,58 @@ <string>Inversion:</string> </property> </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>textLabel11</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Bandwidth:</string> + </property> + </widget> + <widget class="QComboBox" row="3" column="1"> + <property name="name"> + <cstring>bandwidthComb</cstring> + </property> + </widget> + <widget class="QLabel" row="4" column="0"> + <property name="name"> + <cstring>textLabel1_3</cstring> + </property> + <property name="text"> + <string>Type:</string> + </property> + </widget> + <widget class="QComboBox" row="4" column="1"> + <property name="name"> + <cstring>stypeComb</cstring> + </property> + </widget> + <widget class="QComboBox" row="4" column="3"> + <property name="name"> + <cstring>rolloffComb</cstring> + </property> + </widget> + <widget class="QLabel" row="4" column="2"> + <property name="name"> + <cstring>textLabel2_4</cstring> + </property> + <property name="text"> + <string>Roll off:</string> + </property> + </widget> + <widget class="QComboBox" row="3" column="3"> + <property name="name"> + <cstring>guardComb</cstring> + </property> + </widget> </grid> </widget> <spacer> @@ -610,7 +636,7 @@ <property name="sizeHint"> <size> <width>20</width> - <height>98</height> + <height>166</height> </size> </property> </spacer> diff --git a/kaffeine/src/input/dvb/dvbcam.cpp b/kaffeine/src/input/dvb/dvbcam.cpp index 1cb5b86..e525f6d 100644 --- a/kaffeine/src/input/dvb/dvbcam.cpp +++ b/kaffeine/src/input/dvb/dvbcam.cpp @@ -1,6 +1,7 @@ /* * dvbcam.cpp * + * Copyright (C) 2008 Christophe Thommeret <hftom@free.fr> * Copyright (C) 2006 Christoph Pfister <christophpfister@gmail.com> * * code based on ca_zap (LGPL) @@ -29,173 +30,48 @@ #include <sys/poll.h> #include <linux/dvb/ca.h> -#include <libdvbapi/dvbca.h> -#include <libdvbapi/dvbdemux.h> -#include <libdvben50221/en50221_app_ai.h> -#include <libdvben50221/en50221_app_ca.h> -#include <libdvben50221/en50221_app_rm.h> -#include <libdvben50221/en50221_app_tags.h> -#include <libdvben50221/en50221_session.h> -#include <libucsi/mpeg/section.h> - +#include <qapplication.h> #include <qthread.h> #include <qstring.h> +#include <qspinbox.h> +#include <qlabel.h> +#include <qtextbrowser.h> +#include <qlineedit.h> +#include <qpushbutton.h> #include "dvbcam.h" -class DvbCamCamHandler -{ -public: - virtual ~DvbCamCamHandler(); - - bool init(); - - virtual void poll() = 0; - virtual bool registerCam(int ca_fd, uint8_t slot) = 0; - - bool sendPmt(char *pmt_buffer, int size); - -protected: - DvbCamCamHandler(); - - static int infoCallback(void *arg, uint8_t slot_id, uint16_t session_number, uint32_t ca_id_count, uint16_t *ca_ids); - - virtual bool sub_init() = 0; - - void *AiResource; - void *CaResource; - en50221_app_send_functions SendFuncs; - - volatile int SessionNumber; -}; - -class DvbCamCamThread : protected QThread -{ -public: - DvbCamCamThread(int adapter, int ca_device, int ci_type); - ~DvbCamCamThread(); - - void start(); - void stop(); - void wait(); - - bool processPmt(int demux_fd); - -private: - void run(); - - int Adapter; - int CaDevice; - int ciType; - - DvbCamCamHandler *CamHandler; - - char PmtBuffer[4096]; // we imply that processPmt is only once called - - volatile int PmtSize; // PmtSize <= 0 means PmtBuffer invalid - volatile bool Stopped; -}; - -class DvbCamPmtThread : protected QThread -{ -public: - DvbCamPmtThread(DvbCamCamThread *cam_thread, int adapter, int demux_device, int service_id); - ~DvbCamPmtThread(); - - void start(); - void stop(); - void wait(); - -private: - int createSectionFilter(uint16_t pid, uint8_t table_id); - int processPat(int demux_fd); - void run(); +#define TIMER_EVENT_MMI_OPEN 500 +#define TIMER_EVENT_MMI_CLOSE 501 +#define TIMER_EVENT_CAM_READY 502 - DvbCamCamThread *CamThread; - int Adapter; - int DemuxDevice; - int ServiceId; - volatile bool Stopped; -}; -class DvbCamCamHandlerLLCI : public DvbCamCamHandler -{ -public: - DvbCamCamHandlerLLCI(); - ~DvbCamCamHandlerLLCI(); - -private: - struct SlResource - { - en50221_app_public_resource_id resid; - uint32_t binary_resource_id; - en50221_sl_resource_callback callback; - void *arg; - }; - - static int llci_rm_enq_callback(void *arg, uint8_t slot_id, uint16_t session_number); - static int llci_rm_reply_callback(void *arg, uint8_t slot_id, uint16_t session_number, uint32_t resource_id_count, uint32_t *resource_ids); - static int llci_rm_changed_callback(void *arg, uint8_t slot_id, uint16_t session_number); - static int llci_lookup_callback(void *arg, uint8_t slot_id, uint32_t requested_resource_id, en50221_sl_resource_callback *callback_out, void **arg_out, uint32_t *connected_resource_id); - static int llci_session_callback(void *arg, int reason, uint8_t slot_id, uint16_t session_number, uint32_t resource_id); - - void poll(); - bool registerCam(int ca_fd, uint8_t slot); - bool sub_init(); - - void *RmResource; - void *SessionLayer; - void *TransportLayer; - - SlResource Resources[3]; -}; - -class DvbCamCamHandlerHLCI : public DvbCamCamHandler -{ -public: - DvbCamCamHandlerHLCI(); - ~DvbCamCamHandlerHLCI(); - -private: - static int hlci_send_data(void *arg, uint16_t session_number, uint8_t *data, uint16_t data_length); - static int hlci_send_datav(void *arg, uint16_t session_number, iovec *vector, int iov_count); - - void poll(); - bool registerCam(int ca_fd, uint8_t slot); - bool sub_init(); -}; - -// class DvbCam - -DvbCam::DvbCam(int adapter, int ca_device, int demux_device, int ci_type) +DvbCam::DvbCam(int adapter, int ca_device, int demux_device, int ci_type, int maxService) { Adapter = adapter; CaDevice = ca_device; DemuxDevice = demux_device; ciType = ci_type; + CamMaxService = maxService; + fprintf(stderr, "DvbCam: CamMaxService = %d\n", CamMaxService); - isRunning = false; + stdcam = NULL; + menuDialog = NULL; - CamThread = NULL; - PmtThread = NULL; - - // at that time, we do reset in cam_thread - /*if ( ciType!=CA_CI ) { //do not reset HLCI - int ca_fd = dvbca_open( Adapter, CaDevice ); - if(ca_fd < 0) // should not happen - fprintf(stderr, "CamThread: [error] opening ca device failed\n"); - else { - if(dvbca_reset(ca_fd, 0)) - fprintf(stderr, "CamThread: [error] resetting cam slot failed\n"); - close(ca_fd); - } - }*/ + sidList.setAutoDelete( true ); + + isRunning = true; + start(); } DvbCam::~DvbCam() { - stop(); + isRunning = false; + wait(); + sidMutex.lock(); + sidList.clear(); + sidMutex.unlock(); } int DvbCam::probe( int adapter, int ca_device ) @@ -251,676 +127,786 @@ int DvbCam::probe( int adapter, int ca_device ) return -1; } -void DvbCam::restart(int service_id) +bool DvbCam::canPlay( ChannelDesc *chan ) { - stop(); - - isRunning = true; - sid = service_id; - - CamThread = new DvbCamCamThread(Adapter, CaDevice, ciType); - CamThread->start(); + int i, n=0; - PmtThread = new DvbCamPmtThread(CamThread, Adapter, DemuxDevice, service_id); - PmtThread->start(); -} - -void DvbCam::stop() -{ - if(PmtThread != NULL) { - PmtThread->stop(); - } - if(CamThread != NULL) { - CamThread->stop(); - } - if(PmtThread != NULL) { - PmtThread->wait(); - delete PmtThread; - PmtThread = NULL; - } - if(CamThread != NULL) { - CamThread->wait(); - delete CamThread; // be careful about deletion: PmtThread uses CamThread internally - CamThread = NULL; + QMutexLocker locker( &sidMutex ); + for ( i=0; i<sidList.count(); ++i ) { + if ( sidList.at(i)->getState()<CamService::Remove ) + n++; + if ( sidList.at(i)->getChannel().name==chan->name ) + return true; } - isRunning = false; -} - -// class DvbCamCamThread - -DvbCamCamThread::DvbCamCamThread(int adapter, int ca_device, int ci_type) -{ - Adapter = adapter; - CaDevice = ca_device; - ciType = ci_type; - - CamHandler = NULL; -} - -DvbCamCamThread::~DvbCamCamThread() -{ - wait(); // should never be necessary + return ( n<CamMaxService ); } -void DvbCamCamThread::start() +void DvbCam::startService( ChannelDesc *chan ) { - PmtSize = 0; - Stopped = false; - QThread::start(); -} - -void DvbCamCamThread::stop() -{ - Stopped = true; + int i; + QMutexLocker locker( &sidMutex ); + for ( i=0; i<sidList.count(); ++i ) { + if ( sidList.at(i)->getChannel().name==chan->name ) { + sidList.at(i)->restart(); + return; + } + } + sidList.append( new CamService( Adapter, DemuxDevice, chan, CamMaxService ) ); } -void DvbCamCamThread::wait() +void DvbCam::stopService( ChannelDesc *chan ) { - QThread::wait(); + int i; + QMutexLocker locker( &sidMutex ); + for ( i=0; i<sidList.count(); ++i ) { + if ( sidList.at(i)->getChannel().name==chan->name ) { + sidList.at(i)->setState( CamService::Remove ); + return; + } + } } -bool DvbCamCamThread::processPmt(int demux_fd) +void DvbCam::resendPmts() { - // read section - char si_buf[4096]; - int size = read(demux_fd, si_buf, sizeof(si_buf)); - if(size <= 0) { - return false; - } - - // parse section - section *parsed_section = section_codec(reinterpret_cast<unsigned char *> (si_buf), size); - if(parsed_section == NULL) { - return false; - } - - // parse section_ext - section_ext *parsed_section_ext = section_ext_decode(parsed_section, 1); // crc check on - if(parsed_section_ext == NULL) { - return false; - } - - // parse pmt - mpeg_pmt_section *parsed_pmt = mpeg_pmt_section_codec(parsed_section_ext); - if(parsed_pmt == NULL) { - return false; - } - - // translate it into a cam pmt - PmtSize = en50221_ca_format_pmt(parsed_pmt, reinterpret_cast<unsigned char *> (PmtBuffer), sizeof(PmtBuffer), 0, CA_LIST_MANAGEMENT_ONLY, CA_PMT_CMD_ID_OK_DESCRAMBLING); - if(PmtSize <= 0) { - return false; + int i; + QMutexLocker locker( &sidMutex ); + for ( i=0; i<sidList.count(); ++i ) { + if ( sidList.at(i)->getState()==CamService::Added ) { + sidList.at(i)->setState( CamService::Ready ); + } } - - // the DvbCamCamThread will send it to the cam - return true; } -void DvbCamCamThread::run() +void DvbCam::run() { + int i, reset_loop, query_loop, state_loop; + bool cam_ready = false; + fprintf(stderr, "CamThread: started\n"); int ca_fd = dvbca_open(Adapter, CaDevice); - if(ca_fd < 0) { - fprintf(stderr, "CamThread: [error] opening ca device failed\n"); + if ( ca_fd<0 ) { + fprintf( stderr, "CamThread: [error] opening ca device failed\n" ); return; } - fprintf(stderr, "CamThread: just using the first cam slot\n"); + //fprintf(stderr, "CamThread: just using the first cam slot\n"); - if ( ciType!=CA_CI ) { // do not reset HLCI - if(dvbca_reset(ca_fd, 0)) { - fprintf(stderr, "CamThread: [error] resetting cam slot failed\n"); - close(ca_fd); - return; + reset_loop=0; + while ( isRunning && reset_loop++<6 && !cam_ready ) { + if ( ciType!=CA_CI ) { // do not reset HLCI + if ( dvbca_reset(ca_fd, 0) ) { + fprintf( stderr, "CamThread: [error] resetting cam slot failed\n" ); + //close( ca_fd ); + //ca_fd = -1; + //return; + usleep(1000000); + continue; + } + fprintf( stderr, "CamThread: reset cam slot\n" ); } - } - while(!Stopped) { - bool cam_ready = false; - switch(dvbca_get_cam_state(ca_fd, 0)) { - case DVBCA_CAMSTATE_MISSING: { - /*fprintf(stderr, "CamThread: [error] no cam detected\n"); - close(ca_fd); - return; */ // FIXME: find a more reliable solution - break; - } - case DVBCA_CAMSTATE_READY: { - fprintf(stderr, "CamThread: cam 0 is ready\n"); - cam_ready = true; - break; - } - case DVBCA_CAMSTATE_INITIALISING: { - if ( ciType==CA_CI ) { // workaround needed for hlci - fprintf(stderr, "CamThread: cam 0 is ready [hlci workaround]\n"); + state_loop=0; + query_loop=0; + while ( isRunning && state_loop++<30 ) { + switch( dvbca_get_cam_state(ca_fd, 0) ) { + case DVBCA_CAMSTATE_MISSING: { + //fprintf(stderr, "CamThread: [error] no cam detected\n"); + //close(ca_fd); + //return; // FIXME: find a more reliable solution + break; + } + case DVBCA_CAMSTATE_READY: { + fprintf( stderr, "CamThread: cam 0 is ready\n" ); cam_ready = true; + break; + } + case DVBCA_CAMSTATE_INITIALISING: { + fprintf( stderr, "CamThread: cam is initialising\n" ); + if ( ciType==CA_CI ) { // workaround needed for hlci + fprintf(stderr, "CamThread: cam 0 is ready [hlci workaround]\n"); + cam_ready = true; + } + break; + } + default: { + if ( ++query_loop>3 ) { + fprintf(stderr, "CamThread: [error] querying the cam state failed\n"); + close(ca_fd); + ca_fd = -1; + return; + } } - break; } - default: { - fprintf(stderr, "CamThread: [error] querying the cam state failed\n"); - close(ca_fd); - return; + if(cam_ready) { + break; } + usleep(100000); // 100 ms } - if(cam_ready) { - break; - } - usleep(100000); // 100 ms } - if(!Stopped) { + if ( isRunning ) { switch(dvbca_get_interface_type(ca_fd, 0)) { case DVBCA_INTERFACE_LINK: { fprintf(stderr, "CamThread: LLCI cam slot detected\n"); - CamHandler = new DvbCamCamHandlerLLCI(); break; } case DVBCA_INTERFACE_HLCI: { fprintf(stderr, "CamThread: HLCI cam slot detected\n"); - CamHandler = new DvbCamCamHandlerHLCI(); break; } default: { fprintf(stderr, "CamThread: [error] unknown cam slot type\n"); close(ca_fd); + ca_fd = -1; return; } } } - if(!Stopped) { - if(!CamHandler->init()) { - fprintf(stderr, "CamThread: [error] cam slot initialization failed\n"); - delete CamHandler; - CamHandler = NULL; - close(ca_fd); - return; - } - } + close(ca_fd); + ca_fd = -1; - if(!Stopped) { - if(!CamHandler->registerCam(ca_fd, 0)) { - fprintf(stderr, "CamThread: [error] registering cam 0 failed\n"); - delete CamHandler; - CamHandler = NULL; - close(ca_fd); + if ( isRunning ) { + if ( !init() ) { + fprintf(stderr, "CamThread: [error] cam slot initialisation failed\n"); return; } } + fprintf(stderr, "CamThread: cam slot initialised\n"); - while(!Stopped) { - CamHandler->poll(); - if(PmtSize > 0) { - if(CamHandler->sendPmt(PmtBuffer, PmtSize)) { - fprintf(stderr, "CamThread: pmt sent to cam\n"); - PmtSize = 0; + CamService *cs; + while ( isRunning ) { + if ( stdcam->stdcam->poll( stdcam->stdcam )!=EN50221_STDCAM_CAM_OK ) { + usleep( 100000 ); + continue; + } + sidMutex.lock(); + for ( i=0; i<sidList.count(); ++i ) { + cs = sidList.at(i); + if ( cs->getState()==CamService::Remove ) { + if ( sendPmt( cs->caPmt, cs->caPmtSize ) ) { + fprintf( stderr, "CamThread: %s removed from camlist\n", cs->getChannel().name.ascii() ); + sidList.remove( cs ); + --i; + } + else + fprintf( stderr, "CamThread: %s failed removing from camlist\n", cs->getChannel().name.ascii() ); + stdcam->stdcam->poll( stdcam->stdcam ); + usleep(100000); + } + else if ( cs->getState()==CamService::Destroy ) { + fprintf( stderr, "CamThread: %s service deleted\n", cs->getChannel().name.ascii() ); + sidList.remove( cs ); + --i; } } + for ( i=0; i<sidList.count(); ++i ) { + cs = sidList.at(i); + if ( cs->getState()==CamService::Ready ) { + if ( sendPmt( cs->caPmt, cs->caPmtSize ) ) { + cs->setState( CamService::Added ); + fprintf( stderr, "CamThread: %s pmt sent to cam\n", cs->getChannel().name.ascii() ); + } + else + fprintf( stderr, "CamThread: %s pmt failed sending to cam\n", cs->getChannel().name.ascii() ); + stdcam->stdcam->poll( stdcam->stdcam ); + usleep(100000); + } + } + sidMutex.unlock(); + usleep( 10000 ); //sleep a bit } fprintf(stderr, "CamThread: stopping requested\n"); - delete CamHandler; - CamHandler = NULL; - close(ca_fd); + if ( stdcam ) { + if (stdcam->stdcam->destroy) + stdcam->stdcam->destroy(stdcam->stdcam, 1); + en50221_sl_destroy( SessionLayer ); + en50221_tl_destroy( TransportLayer ); + delete stdcam; + } fprintf(stderr, "CamThread: stopped\n"); return; } -// class DvbCamPmtThread - -DvbCamPmtThread::DvbCamPmtThread(DvbCamCamThread *cam_thread, int adapter, int demux_device, int service_id) +bool DvbCam::init() { - CamThread = cam_thread; - Adapter = adapter; - DemuxDevice = demux_device; - ServiceId = service_id; + TransportLayer = en50221_tl_create(1, 16); + if ( TransportLayer==NULL ) { + fprintf(stderr, "Failed to create transport layer\n"); + return false; + } + SessionLayer = en50221_sl_create(TransportLayer, 16); + if ( SessionLayer==NULL ) { + fprintf(stderr, "Failed to create session layer\n"); + en50221_tl_destroy( TransportLayer ); + return false; + } + en50221_stdcam *sc = en50221_stdcam_create( Adapter, 0, TransportLayer, SessionLayer ); + if ( sc==NULL ) { + en50221_sl_destroy( SessionLayer ); + en50221_tl_destroy( TransportLayer ); + fprintf(stderr, "Failed to create stdcam\n"); + return false; + } + + stdcam = new StandardCam( sc, this ); + + // hook up the AI callbacks + if ( stdcam->stdcam->ai_resource ) { + en50221_app_ai_register_callback( stdcam->stdcam->ai_resource, aiCallback, stdcam ); + } + + // hook up the CA callbacks + if ( stdcam->stdcam->ca_resource ) { + en50221_app_ca_register_info_callback( stdcam->stdcam->ca_resource, infoCallback, stdcam ); + } + + // hook up the MMI callbacks + if ( stdcam->stdcam->mmi_resource ) { + en50221_app_mmi_register_close_callback( stdcam->stdcam->mmi_resource, mmi_close_callback, stdcam ); + en50221_app_mmi_register_display_control_callback( stdcam->stdcam->mmi_resource, mmi_display_control_callback, stdcam ); + en50221_app_mmi_register_enq_callback( stdcam->stdcam->mmi_resource, mmi_enq_callback, stdcam ); + en50221_app_mmi_register_menu_callback( stdcam->stdcam->mmi_resource, mmi_menu_callback, stdcam ); + en50221_app_mmi_register_list_callback( stdcam->stdcam->mmi_resource, mmi_menu_callback, stdcam ); + } else { + fprintf(stderr, "CAM Menus are not supported by this interface hardware\n"); + } + + return true; } -DvbCamPmtThread::~DvbCamPmtThread() +bool DvbCam::sendPmt( unsigned char *pmt_buffer, int size ) { - wait(); // should never be necessary + if ( !stdcam ) + return false; + if ( en50221_app_ca_pmt( stdcam->stdcam->ca_resource, stdcam->stdcam->ca_session_number, pmt_buffer, size) ) + return false; + + return true; } -void DvbCamPmtThread::start() +int DvbCam::infoCallback(void *arg, uint8_t slot_id, uint16_t session_number, uint32_t ca_id_count, uint16_t *ca_ids) { - Stopped = false; - QThread::start(); + StandardCam *std = (StandardCam*)arg; + (void)slot_id; + (void)session_number; + + fprintf(stderr, "CAM supports the following ca system ids:\n"); + uint32_t i; + for ( i=0; i<ca_id_count; i++ ) { + fprintf( stderr, " 0x%04x\n", ca_ids[i]); + } + + QApplication::postEvent( std->dvbcam, new QTimerEvent(TIMER_EVENT_CAM_READY ) ); + + return 0; } -void DvbCamPmtThread::stop() +int DvbCam::aiCallback(void *arg, uint8_t slot_id, uint16_t session_number, uint8_t application_type, uint16_t application_manufacturer, uint16_t manufacturer_code, uint8_t menu_string_length, uint8_t *menu_string) { - Stopped = true; + StandardCam *std = (StandardCam*)arg; + (void)slot_id; + (void)session_number; + + fprintf(stderr, "CAM Application type: %02x\n", application_type); + std->dvbcam->setAppType( QString("0x%1").arg(application_type, 0, 16 ) ); + fprintf(stderr, "CAM Application manufacturer: %04x\n", application_manufacturer); + std->dvbcam->setAppManu( QString("0x%1").arg(application_manufacturer, 0, 16 ) ); + fprintf(stderr, "CAM Manufacturer code: %04x\n", manufacturer_code); + std->dvbcam->setManuCode( QString("0x%1").arg(manufacturer_code, 0, 16 ) ); + fprintf(stderr, "CAM Menu string: %.*s\n", menu_string_length, menu_string); + QString s = (const char*)menu_string; + s.truncate( menu_string_length ); + std->dvbcam->setMenuString( s ); + return 0; } -void DvbCamPmtThread::wait() +int DvbCam::mmi_close_callback(void *arg, uint8_t slot_id, uint16_t session_number, uint8_t cmd_id, uint8_t delay) { - QThread::wait(); + fprintf( stderr,"mmi_close_callback, delay=%d\n",delay); + StandardCam *std = (StandardCam*)arg; + (void) slot_id; + (void) session_number; + (void) cmd_id; + (void) delay; + + // note: not entirely correct as its supposed to delay if asked + std->mmi_state = MMI_STATE_CLOSED; + QApplication::postEvent( std->dvbcam, new QTimerEvent(TIMER_EVENT_MMI_CLOSE ) ); + return 0; } -int DvbCamPmtThread::createSectionFilter(uint16_t pid, uint8_t table_id) +int DvbCam::mmi_display_control_callback(void *arg, uint8_t slot_id, uint16_t session_number, uint8_t cmd_id, uint8_t mmi_mode) { - // open the demuxer - int demux_fd = dvbdemux_open_demux(Adapter, DemuxDevice, 0); - if(demux_fd < 0) { - return -1; + fprintf( stderr,"mmi_display_control_callback\n"); + struct en50221_app_mmi_display_reply_details reply; + StandardCam *std = (StandardCam*)arg; + (void) slot_id; + + // don't support any commands but set mode + if ( cmd_id!=MMI_DISPLAY_CONTROL_CMD_ID_SET_MMI_MODE ) { + en50221_app_mmi_display_reply( std->stdcam->mmi_resource, session_number, MMI_DISPLAY_REPLY_ID_UNKNOWN_CMD_ID, &reply ); + return 0; } - // create a section filter - uint8_t filter[18] = {table_id}; - uint8_t mask[18] = {0xff}; - if(dvbdemux_set_section_filter(demux_fd, pid, filter, mask, 1, 1)) { // crc check on - close(demux_fd); - return -1; + // we only support high level mode + if ( mmi_mode!=MMI_MODE_HIGH_LEVEL ) { + en50221_app_mmi_display_reply( std->stdcam->mmi_resource, session_number, MMI_DISPLAY_REPLY_ID_UNKNOWN_MMI_MODE, &reply ); + return 0; } - return demux_fd; + // ack the high level open + reply.u.mode_ack.mmi_mode = mmi_mode; + en50221_app_mmi_display_reply( std->stdcam->mmi_resource, session_number, MMI_DISPLAY_REPLY_ID_MMI_MODE_ACK, &reply ); + std->mmi_state = MMI_STATE_OPEN; + return 0; } -int DvbCamPmtThread::processPat(int demux_fd) +int DvbCam::mmi_enq_callback(void *arg, uint8_t slot_id, uint16_t session_number, uint8_t blind_answer, uint8_t expected_answer_length, + uint8_t *text, uint32_t text_size) { - // read section - char si_buf[4096]; - int size = read(demux_fd, si_buf, sizeof(si_buf)); - if(size < 0) { - return -1; - } + fprintf( stderr,"mmi_enq_callback\n"); + StandardCam *std = (StandardCam*)arg; + (void) slot_id; + (void) session_number; - // parse section - section *parsed_section = section_codec(reinterpret_cast<unsigned char *> (si_buf), size); - if(parsed_section == NULL) { - return -1; - } + QString s; - // parse section_ext - section_ext *parsed_section_ext = section_ext_decode(parsed_section, 1); // crc check on - if(parsed_section_ext == NULL) { - return -1; - } + QMutexLocker locker( &std->mutex ); - // parse pat - mpeg_pat_section *parsed_pat = mpeg_pat_section_codec(parsed_section_ext); - if(parsed_pat == NULL) { - return -1; - } + std->menuList.clear(); + fprintf(stderr, "%.*s: ", text_size, text); + s = (const char*)text; + s.truncate( text_size ); + std->menuList.append( s ); + fflush(stdout); - // try and find the requested program - mpeg_pat_program *cur_program; - mpeg_pat_section_programs_for_each(parsed_pat, cur_program) { - if(cur_program->program_number == ServiceId) { - return cur_program->pid; - } - } + std->mmi_enq_blind = blind_answer; + std->mmi_enq_length = expected_answer_length; + std->mmi_state = MMI_STATE_ENQ; + std->menuType = MMI_MENU; - fprintf(stderr, "PmtThread: [warning] the requested service id couldn't be found\n"); - - return -1; + return 0; } -void DvbCamPmtThread::run() +int DvbCam::mmi_menu_callback(void *arg, uint8_t slot_id, uint16_t session_number, struct en50221_app_mmi_text *title, + struct en50221_app_mmi_text *sub_title, struct en50221_app_mmi_text *bottom, uint32_t item_count, + struct en50221_app_mmi_text *items, uint32_t item_raw_length, uint8_t *items_raw) { - fprintf(stderr, "PmtThread: started\n"); + fprintf( stderr,"mmi_menu_callback, session=%d\n",session_number); + StandardCam *std = (StandardCam*)arg; + (void) slot_id; + (void) session_number; + (void) item_raw_length; + (void) items_raw; - int demux_fd = createSectionFilter(TRANSPORT_PAT_PID, stag_mpeg_program_association); - if(demux_fd < 0) { - fprintf(stderr, "PmtThread: [error] opening demux device failed\n"); - return; - } + QString s; - pollfd poll_desc; - poll_desc.fd = demux_fd; - poll_desc.events = POLLIN | POLLPRI; - while(!Stopped) { - int ret = poll(&poll_desc, 1, 100); // 100 ms - if(ret < 0) { - fprintf(stderr, "PmtThread: [error] polling demux device failed\n"); - close(demux_fd); - return; - } - if((ret > 0) && (poll_desc.revents != 0) && ((poll_desc.revents & ~(POLLIN | POLLPRI)) == 0)) { - int processed_pat = processPat(demux_fd); - if(processed_pat >= 0) { - close(demux_fd); - demux_fd = createSectionFilter(processed_pat, stag_mpeg_program_map); - if(demux_fd < 0) { - fprintf(stderr, "PmtThread: [error] opening demux device failed\n"); - return; - } - poll_desc.fd = demux_fd; - break; - } - } - } + QMutexLocker locker( &std->mutex ); + std->menuList.clear(); - while(!Stopped) { - int ret = poll(&poll_desc, 1, 100); // 100 ms - if(ret < 0) { - fprintf(stderr, "PmtThread: [error] polling demux device failed\n"); - close(demux_fd); - return; - } - if((ret > 0) && (poll_desc.revents != 0) && ((poll_desc.revents & ~(POLLIN | POLLPRI)) == 0)) { - if(CamThread->processPmt(demux_fd)) { - fprintf(stderr, "PmtThread: new pmt received\n"); - close(demux_fd); - fprintf(stderr, "PmtThread: stopped\n"); - return; - } - } + fprintf(stderr, "------------------------------\n"); + + if (title->text_length) { + fprintf(stderr, "%.*s\n", title->text_length, title->text); + s = (const char*)title->text; + s.truncate( title->text_length ); + std->menuList.append( s ); + } + if (sub_title->text_length) { + fprintf(stderr, "%.*s\n", sub_title->text_length, sub_title->text); + s = (const char*)sub_title->text; + s.truncate( sub_title->text_length ); + std->menuList.append( s ); } - fprintf(stderr, "PmtThread: stopping requested\n"); + uint32_t i; + fprintf(stderr, "0. Quit menu\n"); + std->menuList.append( "0. Quit menu" ); + for(i=0; i< item_count; i++) { + fprintf(stderr, "%i. %.*s\n", i+1, items[i].text_length, items[i].text); + s = (const char*)items[i].text; + s.truncate( items[i].text_length ); + std->menuList.append( QString("%1. %2").arg(i+1).arg(s) ); - close(demux_fd); + } - fprintf(stderr, "PmtThread: stopped\n"); - return; -} + if (bottom->text_length) { + fprintf(stderr, "%.*s\n", bottom->text_length, bottom->text); + s = (const char*)bottom->text; + s.truncate( bottom->text_length ); + std->menuList.append( s ); + } + fflush(stdout); -// class DvbCamCamHandler + std->mmi_state = MMI_STATE_MENU; + std->menuType = MMI_MENU; -DvbCamCamHandler::DvbCamCamHandler() -{ - AiResource = NULL; - CaResource = NULL; + QApplication::postEvent( std->dvbcam, new QTimerEvent(TIMER_EVENT_MMI_OPEN ) ); - SessionNumber = -1; + return 0; } -DvbCamCamHandler::~DvbCamCamHandler() +void DvbCam::timerEvent( QTimerEvent *e ) { - if(CaResource != NULL) { - en50221_app_ca_destroy(CaResource); - CaResource = NULL; - } - if(AiResource != NULL) { - en50221_app_ai_destroy(AiResource); - AiResource = NULL; + switch ( e->timerId() ) { + case TIMER_EVENT_MMI_OPEN: + showMMI(); + break; + case TIMER_EVENT_MMI_CLOSE: + closeMMI(); + break; + case TIMER_EVENT_CAM_READY: + resendPmts(); + break; } } -bool DvbCamCamHandler::init() +void DvbCam::showMMI() { - AiResource = en50221_app_ai_create(&SendFuncs); - CaResource = en50221_app_ca_create(&SendFuncs); - - if(CaResource != NULL) { - en50221_app_ca_register_info_callback(CaResource, infoCallback, this); + if ( !menuDialog && stdcam ) { + menuDialog = new MCamMenuDialog( stdcam ); + connect( menuDialog, SIGNAL(enteredResponse(QString)), this, SLOT(mmiResponse(QString)) ); + menuDialog->exec(); + closeMMI(); } - - return sub_init(); } -bool DvbCamCamHandler::sendPmt(char *pmt_buffer, int size) +void DvbCam::closeMMI() { - if((CaResource != NULL) && (SessionNumber >= 0)) { - if(!en50221_app_ca_pmt(CaResource, SessionNumber, reinterpret_cast<unsigned char *> (pmt_buffer), size)) { - return true; + if ( menuDialog ) { + delete menuDialog; + menuDialog = 0; + if ( stdcam && stdcam->stdcam->mmi_resource ) { + en50221_app_mmi_close( stdcam->stdcam->mmi_resource, stdcam->stdcam->mmi_session_number, MMI_CLOSE_MMI_CMD_ID_IMMEDIATE, 0 ); + stdcam->mmi_state = MMI_STATE_CLOSED; } } - - return false; } -int DvbCamCamHandler::infoCallback(void *arg, uint8_t /*slot_id*/, uint16_t session_number, uint32_t /*ca_id_count*/, uint16_t */*ca_ids*/) +int DvbCam::showCamDialog() { - (static_cast<DvbCamCamHandler *> (arg))->SessionNumber = session_number; - return 0; -} -// class DvbCamCamHandlerLLCI - -#define MAX_CARDS 1 -#define MAX_TC 16 -#define MAX_SESSIONS 16 + CamDialog dlg; + dlg.maxServiceSpin->setValue( getCamMaxService() ); + dlg.appTypeLab->setText( getAppType() ); + dlg.appManuLab->setText( getAppManu() ); + dlg.manuCodeLab->setText( getManuCode() ); + dlg.menuStringLab->setText( getMenuString() ); + connect( dlg.camMenuBtn, SIGNAL(clicked()), this, SLOT(enterMenu()) ); + dlg.exec(); + CamMaxService = dlg.maxServiceSpin->value(); + return CamMaxService; +} -DvbCamCamHandlerLLCI::DvbCamCamHandlerLLCI() +void DvbCam::enterMenu() { - RmResource = NULL; - SessionLayer = NULL; - TransportLayer = NULL; + if ( stdcam && stdcam->stdcam->ai_resource ) + en50221_app_ai_entermenu( stdcam->stdcam->ai_resource, stdcam->stdcam->ai_session_number ); } -DvbCamCamHandlerLLCI::~DvbCamCamHandlerLLCI() +void DvbCam::mmiResponse( QString s ) { - if(SessionLayer != NULL) { - en50221_sl_destroy(SessionLayer); - SessionLayer = NULL; - } - if(TransportLayer != NULL) { - en50221_tl_destroy(TransportLayer); - TransportLayer = NULL; - } - if(RmResource != NULL) { - en50221_app_rm_destroy(RmResource); - RmResource = NULL; + QString res = s.stripWhiteSpace(); + + switch( stdcam->mmi_state ) { + case MMI_STATE_CLOSED: + case MMI_STATE_OPEN: { + en50221_app_ai_entermenu(stdcam->stdcam->ai_resource, stdcam->stdcam->ai_session_number); + fprintf(stderr,"en50221_app_ai_entermenu 2\n"); + break; + } + case MMI_STATE_ENQ: { + if ( res.isEmpty() ) { + en50221_app_mmi_answ( stdcam->stdcam->mmi_resource, stdcam->stdcam->mmi_session_number, MMI_ANSW_ID_CANCEL, NULL, 0); + } + else { + en50221_app_mmi_answ( stdcam->stdcam->mmi_resource, stdcam->stdcam->mmi_session_number, MMI_ANSW_ID_ANSWER, (uint8_t*)res.ascii(), res.length() ); + } + stdcam->mmi_state = MMI_STATE_OPEN; + break; + } + case MMI_STATE_MENU: { + en50221_app_mmi_menu_answ( stdcam->stdcam->mmi_resource, stdcam->stdcam->mmi_session_number, res.toInt() ); + stdcam->mmi_state = MMI_STATE_OPEN; + break; + } } } -int DvbCamCamHandlerLLCI::llci_rm_enq_callback(void *arg, uint8_t /*slot_id*/, uint16_t session_number) + + + +MCamMenuDialog::MCamMenuDialog( StandardCam *sc ) { - uint32_t resource_ids[] = {EN50221_APP_RM_RESOURCEID, EN50221_APP_AI_RESOURCEID, EN50221_APP_CA_RESOURCEID}; - en50221_app_rm_reply(arg, session_number, sizeof(resource_ids) / 4, resource_ids); - return 0; + stdcam = sc; + connect( inputLine, SIGNAL(returnPressed()), this, SLOT(validateClicked()) ); + connect( &readTimer, SIGNAL(timeout()), this, SLOT(setMenu()) ); + readTimer.start( 500 ); } -int DvbCamCamHandlerLLCI::llci_rm_reply_callback(void *arg, uint8_t /*slot_id*/, uint16_t session_number, uint32_t /*resource_id_count*/, uint32_t */*resource_ids*/) +void MCamMenuDialog::setMenu() { - en50221_app_rm_changed(arg, session_number); - return 0; + if ( !stdcam ) + return; + QMutexLocker locker( &stdcam->mutex ); + if ( stdcam->menuType==MMI_MENU ) + menuText->setText( stdcam->menuList.join("\n") ); } -int DvbCamCamHandlerLLCI::llci_rm_changed_callback(void *arg, uint8_t /*slot_id*/, uint16_t session_number) +void MCamMenuDialog::validateClicked() { - en50221_app_rm_enq(arg, session_number); - return 0; + emit enteredResponse( inputLine->text() ); + inputLine->clear(); } -int DvbCamCamHandlerLLCI::llci_lookup_callback(void *arg, uint8_t /*slot_id*/, uint32_t requested_resource_id, en50221_sl_resource_callback *callback_out, void **arg_out, uint32_t *connected_resource_id) + + + + +// class CamService +CamService::CamService( int adapter, int demux_device, ChannelDesc *chan, int maxService ) { - // decode the resource id - en50221_app_public_resource_id resid; - if(!en50221_app_decode_public_resource_id(&resid, requested_resource_id)) { - return -1; - } + Adapter = adapter; + DemuxDevice = demux_device; + CamMaxService = maxService; + channel = *chan; + parsedPmt = NULL; + state = NotReady; + isRunning = true; + start(); +} - // try and find an instance of the resource - const SlResource *Resources = (static_cast<DvbCamCamHandlerLLCI *> (arg))->Resources; - int i; - for(i = 0; i < 3; ++i) { - if((resid.resource_class == Resources[i].resid.resource_class) && (resid.resource_type == Resources[i].resid.resource_type)) { - *callback_out = Resources[i].callback; - *arg_out = Resources[i].arg; - *connected_resource_id = Resources[i].binary_resource_id; - return 0; - } - } - return -1; +CamService::~CamService() +{ + stop(); } -int DvbCamCamHandlerLLCI::llci_session_callback(void *arg, int reason, uint8_t /*slot_id*/, uint16_t session_number, uint32_t resource_id) +void CamService::restart() { - if(reason == S_SCALLBACK_REASON_CAMCONNECTED) { - if(resource_id == EN50221_APP_RM_RESOURCEID) { - void *RmResource = (static_cast<DvbCamCamHandlerLLCI *> (arg))->Resources[0].arg; - en50221_app_rm_enq(RmResource, session_number); - } - else if(resource_id == EN50221_APP_AI_RESOURCEID) { - void *AiResource = (static_cast<DvbCamCamHandlerLLCI *> (arg))->Resources[1].arg; - en50221_app_ai_enquiry(AiResource, session_number); - } - else if(resource_id == EN50221_APP_CA_RESOURCEID) { - void *CaResource = (static_cast<DvbCamCamHandlerLLCI *> (arg))->Resources[2].arg; - en50221_app_ca_info_enq(CaResource, session_number); - } - } - return 0; + setState( NotReady ); } -void DvbCamCamHandlerLLCI::poll() +void CamService::stop() { - if(en50221_tl_poll(TransportLayer)) { - fprintf(stderr, "CamThread: [warning] polling the stack failed\n"); - usleep(10000); // wait 10 ms to not block - } + isRunning = false; + wait(); } -bool DvbCamCamHandlerLLCI::registerCam(int ca_fd, uint8_t slot) +int CamService::createSectionFilter(uint16_t pid, uint8_t table_id) { - // register the slot - int slot_id = en50221_tl_register_slot(TransportLayer, ca_fd, slot, 1000, 100); - if(slot_id < 0) { - return false; + // open the demuxer + int demux_fd = dvbdemux_open_demux(Adapter, DemuxDevice, 0); + if(demux_fd < 0) { + return -1; } - // create a new connection on the slot - if(en50221_tl_new_tc(TransportLayer, slot_id) < 0) { - return false; + // create a section filter + uint8_t filter[18] = {table_id}; + uint8_t mask[18] = {0xff}; + if(dvbdemux_set_section_filter(demux_fd, pid, filter, mask, 1, 1)) { // crc check on + close(demux_fd); + return -1; } - return true; + return demux_fd; } -bool DvbCamCamHandlerLLCI::sub_init() +int CamService::processPat(int demux_fd) { - // create transport layer - TransportLayer = en50221_tl_create(MAX_CARDS, MAX_TC); - if(TransportLayer == NULL) { - return false; - } + // read section + unsigned char si_buf[4096]; + int size = read( demux_fd, si_buf, sizeof(si_buf) ); + if ( size<0 ) + return -1; - // create session layer - SessionLayer = en50221_sl_create(TransportLayer, MAX_SESSIONS); - if(SessionLayer == NULL) { - en50221_tl_destroy(TransportLayer); - TransportLayer = NULL; - return false; - } + // parse section + section *parsed_section = section_codec( si_buf, size ); + if ( parsed_section==NULL ) + return -1; - // create sendfuncs - SendFuncs.arg = SessionLayer; - SendFuncs.send_data = en50221_sl_send_data; - SendFuncs.send_datav = en50221_sl_send_datav; - - // create the resource manager resource - RmResource = en50221_app_rm_create(&SendFuncs); - en50221_app_decode_public_resource_id(&Resources[0].resid, EN50221_APP_RM_RESOURCEID); - Resources[0].binary_resource_id = EN50221_APP_RM_RESOURCEID; - Resources[0].callback = en50221_app_rm_message; - Resources[0].arg = RmResource; - en50221_app_rm_register_enq_callback(RmResource, llci_rm_enq_callback, RmResource); - en50221_app_rm_register_reply_callback(RmResource, llci_rm_reply_callback, RmResource); - en50221_app_rm_register_changed_callback(RmResource, llci_rm_changed_callback, RmResource); - - // integrate the application information resource - en50221_app_decode_public_resource_id(&Resources[1].resid, EN50221_APP_AI_RESOURCEID); - Resources[1].binary_resource_id = EN50221_APP_AI_RESOURCEID; - Resources[1].callback = en50221_app_ai_message; - Resources[1].arg = AiResource; - - // integrate the ca resource - en50221_app_decode_public_resource_id(&Resources[2].resid, EN50221_APP_CA_RESOURCEID); - Resources[2].binary_resource_id = EN50221_APP_CA_RESOURCEID; - Resources[2].callback = en50221_app_ca_message; - Resources[2].arg = CaResource; - - // register session layer callbacks - en50221_sl_register_lookup_callback(SessionLayer, llci_lookup_callback, this); - en50221_sl_register_session_callback(SessionLayer, llci_session_callback, this); + // parse section_ext + section_ext *parsed_section_ext = section_ext_decode( parsed_section, 1 ); // crc check on + if ( parsed_section_ext==NULL ) + return -1; - return true; -} + // parse pat + mpeg_pat_section *parsed_pat = mpeg_pat_section_codec( parsed_section_ext ); + if ( parsed_pat==NULL ) + return -1; -// class DvbCamCamHandlerHLCI + // try and find the requested program + mpeg_pat_program *cur_program; + mpeg_pat_section_programs_for_each( parsed_pat, cur_program ) { + if ( cur_program->program_number==channel.sid ) + return cur_program->pid; + } -DvbCamCamHandlerHLCI::DvbCamCamHandlerHLCI() -{ -} + fprintf( stderr, "CamService (%s): [warning] channel couldn't be found in PAT\n", channel.name.ascii() ); -DvbCamCamHandlerHLCI::~DvbCamCamHandlerHLCI() -{ + return -1; } -int DvbCamCamHandlerHLCI::hlci_send_data(void *arg, uint16_t /*session_number*/, uint8_t *data, uint16_t data_length) +int CamService::processPmt( int demux_fd ) { - return dvbca_hlci_write(static_cast<int> (reinterpret_cast<intptr_t> (arg)), data, data_length); -} + // read section + memset( pmtBuffer, 0, sizeof(pmtBuffer) ); + int size = read( demux_fd, pmtBuffer, sizeof(pmtBuffer) ); + if ( size<=0 ) + return -1; -int DvbCamCamHandlerHLCI::hlci_send_datav(void *arg, uint16_t /*session_number*/, iovec *vector, int iov_count) -{ - // calculate the total length of the data to send - uint32_t data_size = 0; - for(int i = 0; i < iov_count; ++i) { - data_size += vector[i].iov_len; - } + // parse section + section *parsed_section = section_codec( pmtBuffer, size ); + if ( parsed_section==NULL ) + return -1; - // allocate memory for it - uint8_t *buf = new uint8_t[data_size]; + // parse section_ext + section_ext *parsed_section_ext = section_ext_decode( parsed_section, 1 ); // crc check on + if ( parsed_section_ext==NULL ) + return -1; - // merge the iovecs - uint8_t *pos = buf; - for(int i = 0; i < iov_count; ++i) { - memcpy(pos, vector[i].iov_base, vector[i].iov_len); - pos += vector[i].iov_len; - } + // parse pmt + struct mpeg_pmt_section *pmt = mpeg_pmt_section_codec( parsed_section_ext ); + if ( pmt==NULL ) + return -1; - // send it - int status = dvbca_hlci_write(static_cast<int> (reinterpret_cast<intptr_t> (arg)), buf, data_size); - delete buf; - return status; + parsedPmt = pmt; + return parsedPmt->head.version_number; } -void DvbCamCamHandlerHLCI::poll() +void CamService::setState( PmtState st ) { - // we do nothing here for the moment - usleep(100000); // 100 ms + QMutexLocker locker( &mutex ); + switch ( st ) { + case Ready: { + int listmgnt; + if ( CamMaxService==1 ) + listmgnt = CA_LIST_MANAGEMENT_ONLY; + else + listmgnt = CA_LIST_MANAGEMENT_ADD; + if ( state>Ready ) + listmgnt = CA_LIST_MANAGEMENT_UPDATE; + if ( setCaPmt( listmgnt, CA_PMT_CMD_ID_OK_DESCRAMBLING ) ) + state = st; + break; + } + case Remove: { + if ( state!=Added ) + state = Destroy; + else if ( setCaPmt( CA_LIST_MANAGEMENT_UPDATE, CA_PMT_CMD_ID_NOT_SELECTED ) ) + state = st; + break; + } + default: { + state = st; + } + } } -bool DvbCamCamHandlerHLCI::registerCam(int ca_fd, uint8_t /*slot*/) +int CamService::getState() { - SendFuncs.arg = reinterpret_cast<void *> (ca_fd); - - // get application information - if(en50221_app_ai_enquiry(AiResource, 0)) { - fprintf(stderr, "CamThread: [DEBUG #1]\n"); - return false; - } - - uint8_t buf[256]; - int size = dvbca_hlci_read(ca_fd, TAG_APP_INFO, buf, sizeof(buf)); - if(size <= 0) { - fprintf(stderr, "CamThread: [DEBUG #2]\n"); - return false; - } + QMutexLocker locker( &mutex ); + return state; +} - if(en50221_app_ai_message(AiResource, 0, 0, EN50221_APP_AI_RESOURCEID, buf, size)) { - fprintf(stderr, "CamThread: [DEBUG #3]\n"); +bool CamService::setCaPmt( int list_management, int cmd_id ) +{ + if ( !parsedPmt ) return false; - } - // FIXME: try to change this soon - buf[0] = TAG_CA_INFO >> 16; - buf[1] = TAG_CA_INFO >> 8; - buf[2] = TAG_CA_INFO; - buf[3] = 0; - if(en50221_app_ca_message(CaResource, 0, 0, EN50221_APP_CA_RESOURCEID, buf, 4)) { - fprintf(stderr, "CamThread: [DEBUG #4]\n"); + caPmtSize = en50221_ca_format_pmt( parsedPmt, caPmt, sizeof(caPmt), 0, list_management, cmd_id ); + if ( caPmtSize<=0 ) return false; - } - - fprintf(stderr, "CamThread: [DEBUG #5]\n"); return true; } -bool DvbCamCamHandlerHLCI::sub_init() +void CamService::run() { - // create sendfuncs - SendFuncs.arg = NULL; - SendFuncs.send_data = hlci_send_data; - SendFuncs.send_datav = hlci_send_datav; + int i, pmtVersion=-1; + int demux_fd=-1; - return true; + fprintf( stderr, "CamService (%s): started\n", channel.name.ascii() ); + + while ( isRunning ) { +loopLabel: + demux_fd = createSectionFilter( TRANSPORT_PAT_PID, stag_mpeg_program_association ); + if ( demux_fd<0 ) { + fprintf( stderr, "CamService (%s): [error] opening demux device failed\n", channel.name.ascii() ); + demux_fd = -1; + usleep( 100000 ); + goto loopLabel; + } + + pollfd poll_desc; + poll_desc.fd = demux_fd; + poll_desc.events = POLLIN | POLLPRI; + while ( isRunning ) { + int ret = poll( &poll_desc, 1, 1000 ); + if ( ret<0 ) { + fprintf( stderr, "CamService (%s): [error] polling demux device failed\n", channel.name.ascii() ); + close( demux_fd ); + demux_fd = -1; + usleep( 100000 ); + goto loopLabel; + } + if ( ret>0 ) { + int processed_pat = processPat( demux_fd ); + if ( processed_pat>=0 ) { + close( demux_fd ); + demux_fd = -1; + demux_fd = createSectionFilter( processed_pat, stag_mpeg_program_map ); + if ( demux_fd<0 ) { + fprintf( stderr, "CamService (%s): [error] opening demux device failed\n", channel.name.ascii() ); + demux_fd = -1; + usleep( 100000 ); + goto loopLabel; + } + poll_desc.fd = demux_fd; + break; + } + else + usleep( 10000 ); + } + else + usleep( 10000 ); + } + + while ( isRunning ) { + int ret = poll( &poll_desc, 1, 1000 ); + if ( ret<0 ) { + fprintf( stderr, "CamService (%s): [error] polling demux device failed\n", channel.name.ascii() ); + close( demux_fd ); + demux_fd = -1; + usleep( 100000 ); + goto loopLabel; + } + if ( ret>0 ) { + //fprintf( stderr, "CamService (%s): parsing pmt\n", channel.name.ascii() ); + i = processPmt( demux_fd ); + if ( i==-1 ) + usleep( 10000 ); + else { + if ( i!=pmtVersion || getState()<Ready ) { + fprintf( stderr, "CamService (%s): new pmt received\n", channel.name.ascii() ); + setState( Ready ); + pmtVersion = i; + } + i = 200; + while ( i-- && isRunning ) + usleep( 10000 ); + } + } + else + usleep( 10000 ); + } + } + + if ( demux_fd != -1 ) + close( demux_fd ); + fprintf( stderr, "CamService (%s): stopped\n", channel.name.ascii() ); } diff --git a/kaffeine/src/input/dvb/dvbcam.h b/kaffeine/src/input/dvb/dvbcam.h index 47a4012..ec9bf45 100644 --- a/kaffeine/src/input/dvb/dvbcam.h +++ b/kaffeine/src/input/dvb/dvbcam.h @@ -1,6 +1,7 @@ /* * dvbcam.h * + * Copyright (C) 2008 Christophe Thommeret <hftom@free.fr> * Copyright (C) 2006 Christoph Pfister <christophpfister@gmail.com> * * This program is free software; you can redistribute it and/or modify @@ -21,32 +22,182 @@ #ifndef DVBCAM_H #define DVBCAM_H -class DvbCamCamThread; -class DvbCamPmtThread; +#include <libdvbapi/dvbca.h> +#include <libdvbapi/dvbdemux.h> +#include <libdvben50221/en50221_app_ai.h> +#include <libdvben50221/en50221_app_ca.h> +#include <libdvben50221/en50221_app_mmi.h> +#include <libdvben50221/en50221_app_rm.h> +#include <libdvben50221/en50221_app_tags.h> +#include <libdvben50221/en50221_session.h> +#include <libdvben50221/en50221_stdcam.h> +#include <libucsi/mpeg/section.h> -class DvbCam +#include <qthread.h> +#include <qmutex.h> +#include <qptrlist.h> + +#include "channeldesc.h" +#include "camdialog.h" +#include "cammenudialog.h" + +#define MMI_STATE_CLOSED 0 +#define MMI_STATE_OPEN 1 +#define MMI_STATE_ENQ 2 +#define MMI_STATE_MENU 3 + +#define MMI_NO_MENU 0 +#define MMI_MENU 1 + + + +class CamService : protected QThread { public: - DvbCam(int adapter, int ca_device, int demux_device, int ci_type); - ~DvbCam(); + enum PmtState{ NotReady=0, Ready, Added, Remove, Destroy }; + CamService( int adapter, int demux_device, ChannelDesc *chan, int maxService ); + ~CamService(); + void setState( PmtState st ); + int getState(); + const ChannelDesc& getChannel() { return channel; } + void restart(); - void restart(int service_id); + unsigned char caPmt[4096]; + int caPmtSize; + +protected: + void run(); + +private: + int createSectionFilter( uint16_t pid, uint8_t table_id ); + int processPat( int demux_fd ); + int processPmt( int demux_fd ); + bool setCaPmt( int list_management, int cmd_id ); void stop(); - bool running() { return isRunning; } - int serviceId() { return sid; } + int Adapter; + int DemuxDevice; + ChannelDesc channel; + unsigned char pmtBuffer[4096]; + struct mpeg_pmt_section *parsedPmt; + PmtState state; + bool isRunning; + QMutex mutex; + int CamMaxService; +}; + + + +class DvbCam; + +class StandardCam +{ +public: + StandardCam( en50221_stdcam *sc, DvbCam *dc ) { + stdcam=sc; + dvbcam=dc; + mmi_state=MMI_STATE_CLOSED; + menuType=MMI_NO_MENU; + } + + en50221_stdcam *stdcam; + DvbCam *dvbcam; + int mmi_state; + int mmi_enq_blind; + int mmi_enq_length; + + int menuType; + QStringList menuList; + + QMutex mutex; +}; + + + +class MCamMenuDialog : public CamMenuDialog +{ + Q_OBJECT +public: + MCamMenuDialog( StandardCam *sc ); +private: + StandardCam *stdcam; + QTimer readTimer; +private slots: + void setMenu(); + void validateClicked(); +signals: + void enteredResponse( QString ); +}; + + + +class DvbCam : public QObject, public QThread +{ + Q_OBJECT +public: + DvbCam(int adapter, int ca_device, int demux_device, int ci_type, int maxService); + ~DvbCam(); + void startService( ChannelDesc *chan ); + void stopService( ChannelDesc *chan ); + bool canPlay( ChannelDesc *chan ); static int probe( int adapter, int ca_device ); + void setAppType( QString s ) { appType=s; } + void setAppManu( QString s ) { appManu=s; } + void setManuCode( QString s ) { manuCode=s; } + void setMenuString( QString s ) { menuString=s; } + QString getAppType() { return appType; } + QString getAppManu() { return appManu; } + QString getManuCode() { return manuCode; } + QString getMenuString() { return menuString; } + int getCamMaxService() { return CamMaxService; } + + int showCamDialog(); + +protected: + void run(); + void timerEvent( QTimerEvent *e ); + +private slots: + void mmiResponse( QString s ); + void showMMI(); + void closeMMI(); + void enterMenu(); + private: + bool init(); + bool sendPmt( unsigned char *pmt_buffer, int size ); + void resendPmts(); + + static int infoCallback(void *arg, uint8_t slot_id, uint16_t session_number, uint32_t ca_id_count, uint16_t *ca_ids); + static int aiCallback(void *arg, uint8_t slot_id, uint16_t session_number, uint8_t application_type, + uint16_t application_manufacturer, uint16_t manufacturer_code, uint8_t menu_string_length, uint8_t *menu_string); + static int mmi_close_callback(void *arg, uint8_t slot_id, uint16_t session_number, uint8_t cmd_id, uint8_t delay); + static int mmi_display_control_callback(void *arg, uint8_t slot_id, uint16_t session_number, uint8_t cmd_id, uint8_t mmi_mode); + static int mmi_enq_callback(void *arg, uint8_t slot_id, uint16_t session_number, uint8_t blind_answer, uint8_t expected_answer_length, + uint8_t *text, uint32_t text_size); + static int mmi_menu_callback(void *arg, uint8_t slot_id, uint16_t session_number, struct en50221_app_mmi_text *title, + struct en50221_app_mmi_text *sub_title, struct en50221_app_mmi_text *bottom, uint32_t item_count, + struct en50221_app_mmi_text *items, uint32_t item_raw_length, uint8_t *items_raw); + int Adapter; int CaDevice; int DemuxDevice; - bool isRunning; - int sid; int ciType; + int CamMaxService; + + bool isRunning; + + QPtrList<CamService> sidList; + QMutex sidMutex; + + QString appType, appManu, manuCode, menuString; + + StandardCam *stdcam; + en50221_session_layer *SessionLayer; + en50221_transport_layer *TransportLayer; - DvbCamCamThread *CamThread; - DvbCamPmtThread *PmtThread; + MCamMenuDialog *menuDialog; }; #endif /* DVBCAM_H */ diff --git a/kaffeine/src/input/dvb/dvbconfig.cpp b/kaffeine/src/input/dvb/dvbconfig.cpp index 746d745..90e0489 100644 --- a/kaffeine/src/input/dvb/dvbconfig.cpp +++ b/kaffeine/src/input/dvb/dvbconfig.cpp @@ -38,6 +38,7 @@ #include "dvbconfig.h" #include "kaffeinedvbplugin.h" +#include "dvbpanel.h" @@ -72,6 +73,21 @@ void MPushButton::isClicked() +MCAMButton::MCAMButton( QWidget *parent, int devNum ) : QPushButton( i18n("CAM"), parent ) +{ + deviceNumber = devNum; + connect( this, SIGNAL(clicked()), this, SLOT(isClicked()) ); +} + + + +void MCAMButton::isClicked() +{ + emit clicked( deviceNumber ); +} + + + MComboBox::MComboBox( QWidget *parent, int devNum, int lnbNum ) : QComboBox( parent ) { deviceNumber = devNum; @@ -109,6 +125,12 @@ Device::Device( int anum, int tnum, fe_type_t t, const QString &n, bool as ) source = ""; canAutoscan= as; tuningTimeout = 1500; + hasCAM = false; + camMaxService = 1; + secMini = 0; + secTwice = 0; + priority = 10; + doS2 = 0; } @@ -134,6 +156,7 @@ DVBconfig::DVBconfig( const QString &dvbConf ) sizeFile = 0; categories.setAutoDelete( true ); devList.setAutoDelete( true ); + readFirst(); startup(); readConfig(); } @@ -187,6 +210,7 @@ void DVBconfig::startup() int i=0, j=0, res, fdFrontend=0; struct dvb_frontend_info info; bool as; + QTime t1; QStringList list, flist; QString s, t; @@ -200,6 +224,11 @@ void DVBconfig::startup() for ( j=0; j<(int)flist.count(); j++ ) { s = list[i]; t = flist[j]; + if ( devList.count()==MAX_DEVICES ) + break; + if ( !probeMfe && t!="frontend0" ) + continue; + t1 = QTime::currentTime(); fdFrontend = open( QString("/dev/dvb/%1/%2").arg( s ).arg( t ).ascii(), O_RDWR); if ( fdFrontend>0 ) { if ( !(res = ioctl( fdFrontend, FE_GET_INFO, &info ) < 0) ) { @@ -212,13 +241,14 @@ void DVBconfig::startup() as = true; else as = false; - fprintf(stderr,"/dev/dvb/%s/%s : opened ( %s )\n", s.ascii(), t.ascii(), info.name ); + fprintf(stderr,"/dev/dvb/%s/%s : opened ( %s ) (%dms)\n", s.ascii(), t.ascii(), info.name, t1.msecsTo(QTime::currentTime()) ); devList.append( new Device( s.replace("adapter","").toInt(), t.replace("frontend","").toInt(), info.type, info.name, as ) ); } close( fdFrontend ); } - else - perror( QString("/dev/dvb/%1/%2").arg( s ).arg( t ).ascii() ); + else { + perror( QString("/dev/dvb/%1/%2 %3/%4").arg( s ).arg( t ).arg( errno ).arg( -EBUSY ).ascii() ); + } } } @@ -292,9 +322,9 @@ bool DVBconfig::localData() bool DVBconfig::haveData() { - if ( !QDir( dvbConfigDir+"dvb-s" ).exists() || !QDir( dvbConfigDir+"dvb-c" ).exists() || !QDir( dvbConfigDir+"dvb-t" ).exists() ) { + if ( !QDir( dvbConfigDir+"dvb-s" ).exists() || !QDir( dvbConfigDir+"dvb-c" ).exists() || !QDir( dvbConfigDir+"dvb-t" ).exists() || !QDir( dvbConfigDir+"atsc" ).exists()) { loadDvbData(0); - if ( !QDir( dvbConfigDir+"dvb-s" ).exists() || !QDir( dvbConfigDir+"dvb-c" ).exists() || !QDir( dvbConfigDir+"dvb-t" ).exists() ) { + if ( !QDir( dvbConfigDir+"dvb-s" ).exists() || !QDir( dvbConfigDir+"dvb-c" ).exists() || !QDir( dvbConfigDir+"dvb-t" ).exists() || !QDir( dvbConfigDir+"atsc" ).exists() ) { if ( !localData() ) return false; } @@ -313,6 +343,7 @@ QStringList DVBconfig::getSourcesList( fe_type_t type ) case FE_QPSK : s = "dvb-s"; break; case FE_QAM : s = "dvb-c"; break; case FE_OFDM : s = "dvb-t"; break; + case FE_ATSC : s = "atsc"; break; default : return list; } list = QDir( dvbConfigDir+s ).entryList( QDir::Files, QDir::Name ); @@ -383,6 +414,14 @@ void DVBconfig::saveDvbChanOrder( int s, int col ) +void DVBconfig::readFirst() +{ + config->setGroup( "DVB Options" ); + probeMfe = config->readNumEntry( "ProbeMFE", 1 ); +} + + + void DVBconfig::readConfig() { QSize size; @@ -413,6 +452,8 @@ void DVBconfig::readConfig() for ( i=0; i<(int)devList.count(); i++ ) { devList.at(i)->source = config->readEntry( QString("DVB%1").arg(i), "" ); devList.at(i)->tuningTimeout = config->readNumEntry( QString("DVB%1_TIMEOUT").arg(i), 1500 ); + devList.at(i)->camMaxService = config->readNumEntry( QString("DVB%1_CAM_MAX").arg(i), 1 ); + devList.at(i)->priority = config->readNumEntry( QString("DVB%1_PRIORITY").arg(i), 10 ); if ( devList.at(i)->type!=FE_QPSK ) continue; devList.at(i)->numLnb = config->readNumEntry( QString("DVB%1_NLNB").arg(i), 1 ); @@ -426,6 +467,9 @@ void DVBconfig::readConfig() devList.at(i)->lnb[j].speed13v = config->readDoubleNumEntry( QString("DVB%1_LNB%2_speed13v").arg(i).arg(j), 2.5 ); devList.at(i)->lnb[j].speed18v = config->readDoubleNumEntry( QString("DVB%1_LNB%2_speed18v").arg(i).arg(j), 1.5 ); } + devList.at(i)->secMini = config->readNumEntry( QString("DVB%1_SEC_MINI").arg(i), 0 ); + devList.at(i)->secTwice = config->readNumEntry( QString("DVB%1_SEC_TWICE").arg(i), 0 ); + devList.at(i)->doS2 = config->readNumEntry( QString("DVB%1_DOS2").arg(i), 0 ); } j = config->readNumEntry( "NumCategories", 0 ); for ( i=0; i<j; i++ ) @@ -442,6 +486,9 @@ void DVBconfig::readConfig() devList.at(i)->usalsLatitude = usalsLatitude; devList.at(i)->usalsLongitude = usalsLongitude; } + ringBufSize = config->readNumEntry( "RingBufSize", 2 ); + if ( ringBufSize<2 ) + ringBufSize = 2; } @@ -463,9 +510,12 @@ void DVBconfig::saveConfig() config->writeEntry( "BroadcastAddress", broadcastAddress ); config->writeEntry( "BroadcastPort", broadcastPort ); config->writeEntry( "SenderPort", senderPort ); + config->writeEntry( "ProbeMFE", probeMfe ); for ( i=0; i<(int)devList.count(); i++ ) { config->writeEntry( QString("DVB%1").arg(i), devList.at(i)->source ); config->writeEntry( QString("DVB%1_TIMEOUT").arg(i), devList.at(i)->tuningTimeout ); + config->writeEntry( QString("DVB%1_PRIORITY").arg(i), devList.at(i)->priority ); + config->writeEntry( QString("DVB%1_CAM_MAX").arg(i), devList.at(i)->camMaxService ); if ( devList.at(i)->type!=FE_QPSK ) continue; config->writeEntry( QString("DVB%1_NLNB").arg(i), devList.at(i)->numLnb ); @@ -479,6 +529,9 @@ void DVBconfig::saveConfig() config->writeEntry( QString("DVB%1_LNB%2_speed13v").arg(i).arg(j), devList.at(i)->lnb[j].speed13v ); config->writeEntry( QString("DVB%1_LNB%2_speed18v").arg(i).arg(j), devList.at(i)->lnb[j].speed18v ); } + config->writeEntry( QString("DVB%1_SEC_MINI").arg(i), devList.at(i)->secMini ); + config->writeEntry( QString("DVB%1_SEC_TWICE").arg(i), devList.at(i)->secTwice ); + config->writeEntry( QString("DVB%1_DOS2").arg(i), devList.at(i)->doS2 ); } config->writeEntry( "NumCategories", categories.count() ); for ( i=0; i<(int)categories.count(); i++ ) { @@ -494,6 +547,7 @@ void DVBconfig::saveConfig() config->writeEntry( "UsalsLatitude", usalsLatitude ); config->writeEntry( "UsalsLongitude", usalsLongitude ); config->writeEntry( "SizeFile", sizeFile ); + config->writeEntry( "RingBufSize", ringBufSize ); config->sync(); } @@ -511,7 +565,7 @@ bool DVBconfig::firstRun() -DvbConfigDialog::DvbConfigDialog( DVBconfig *dc, QWidget *parent, KaffeineDvbPlugin *p ) : +DvbConfigDialog::DvbConfigDialog( DvbPanel *pan, DVBconfig *dc, QWidget *parent, KaffeineDvbPlugin *p ) : KDialogBase ( IconList, i18n("DVB Settings"), Ok|Cancel, Ok, parent, "dvbConfigDialog", true, true ) { QLabel *lab; @@ -529,7 +583,7 @@ DvbConfigDialog::DvbConfigDialog( DVBconfig *dc, QWidget *parent, KaffeineDvbPlu QSpinBox *spin; KPushButton *usals; QWidget *swidg; - QStringList rotorList; rotorList<<i18n("No rotor")<<i18n("USALS rotor")<<i18n("Positions rotor"); + QStringList rotorList; rotorList<<i18n("No rotor")<<i18n("USALS rotor")<<i18n("Positions rotor")<<i18n("External positionner"); dvbConfig = dc; timeoutSpin.setAutoDelete( true ); @@ -558,7 +612,22 @@ DvbConfigDialog::DvbConfigDialog( DVBconfig *dc, QWidget *parent, KaffeineDvbPlu case FE_ATSC : dvbType->setText( i18n("Atsc") ); break; default : dvbType->setText( i18n("Unknown") ); } - grid->addMultiCellWidget( dvbType, gridLine, gridLine, 1, 3 ); + if ( dvbConfig->devList.at(i)->hasCAM ) { + grid->addWidget( dvbType, gridLine, 1 ); + MCAMButton *camb = new MCAMButton( gb, i ); + connect( camb, SIGNAL(clicked(int)), pan, SLOT(camClicked(int)) ); + grid->addWidget( camb, gridLine, 2 ); + } + else + grid->addMultiCellWidget( dvbType, gridLine, gridLine, 1, 3 ); + ++gridLine; + + lab = new QLabel( i18n("Tuner priority (0=Don't use):"), gb ); + grid->addWidget( lab, gridLine, 0 ); + spin = new QSpinBox( 0, 99, 1, gb ); + spin->setValue( dvbConfig->devList.at(i)->priority ); + priority.append( spin ); + grid->addWidget( spin, gridLine, 1 ); ++gridLine; lab = new QLabel( i18n("Tuner timeout :"), gb ); @@ -572,6 +641,11 @@ DvbConfigDialog::DvbConfigDialog( DVBconfig *dc, QWidget *parent, KaffeineDvbPlu ++gridLine; if ( dvbConfig->devList.at(i)->type==FE_QPSK ) { + doS2[i] = new QCheckBox( i18n("S2 capable device"), gb ); + doS2[i]->setChecked( dvbConfig->devList.at(i)->doS2 ); + grid->addWidget( doS2[i], gridLine, 0 ); + ++gridLine; + lab = new QLabel( i18n("Number of LNBs:"), gb ); grid->addWidget( lab, gridLine, 0 ); satNumber[i] = new MSpinBox( gb, i ); @@ -583,6 +657,16 @@ DvbConfigDialog::DvbConfigDialog( DVBconfig *dc, QWidget *parent, KaffeineDvbPlu grid->addWidget( usals, gridLine, 2 ); ++gridLine; + + secMini[i] = new QCheckBox( i18n("Mini DiSEqC (A-B)."), gb ); + secMini[i]->setChecked( dvbConfig->devList.at(i)->secMini ); + secMini[i]->setEnabled( false ); + grid->addWidget( secMini[i], gridLine, 1 ); + secTwice[i] = new QCheckBox( i18n("Send DiSEqC commands twice."), gb ); + secTwice[i]->setChecked( dvbConfig->devList.at(i)->secTwice ); + grid->addWidget( secTwice[i], gridLine, 0 ); + + ++gridLine; lnb0[i] = new MPushButton( gb, i, 0 ); lnb0[i]->setGuiItem( KGuiItem(i18n("LNB 1 settings..."), icon->loadIconSet("hwinfo", KIcon::Small) ) ); @@ -853,9 +937,19 @@ DvbConfigDialog::DvbConfigDialog( DVBconfig *dc, QWidget *parent, KaffeineDvbPlu vb = new QVBoxLayout( page, 6, 6 ); gb = new QGroupBox( "", page ); grid = new QGridLayout( gb, 1, 1, 20, 6 ); + + probeMfe = new QCheckBox( i18n("Probe Multiple-Frontends (Restart required)."), gb ); + probeMfe->setChecked( dvbConfig->probeMfe ); + grid->addWidget( probeMfe, 0, 0 ); + + lab = new QLabel( i18n("LiveShow ringbuffer size (MB) :"), gb ); + grid->addWidget( lab, 1, 0 ); + ringBufSize = new QSpinBox( 2, 99, 1, gb ); + ringBufSize->setValue( dvbConfig->ringBufSize ); + grid->addWidget( ringBufSize, 1, 1 ); lab = new QLabel( i18n("Default charset (restart needed):"), gb ); - grid->addWidget( lab, 0, 0 ); + grid->addWidget( lab, 2, 0 ); charsetComb = new QComboBox( gb ); charsetComb->insertItem( "ISO8859-1" ); charsetComb->insertItem( "ISO6937" ); @@ -863,19 +957,19 @@ DvbConfigDialog::DvbConfigDialog( DVBconfig *dc, QWidget *parent, KaffeineDvbPlu charsetComb->setCurrentItem( 0 ); else if ( dvbConfig->defaultCharset=="ISO6937" ) charsetComb->setCurrentItem( 1 ); - grid->addWidget( charsetComb, 0, 1 ); + grid->addWidget( charsetComb, 2, 1 ); lab = new QLabel( i18n("Update scan data:"), gb ); - grid->addWidget( lab, 1, 0 ); + grid->addWidget( lab, 3, 0 ); updateBtn = new KPushButton( gb ); updateBtn->setGuiItem( KGuiItem(i18n("Download"), icon->loadIconSet("khtml_kget", KIcon::Small) ) ); - grid->addWidget( updateBtn, 1, 1 ); + grid->addWidget( updateBtn, 3, 1 ); lab = new QLabel( i18n("Dump epg's events to \n~/kaffeine_dvb_events.tx:"), gb ); - grid->addWidget( lab, 2, 0 ); + grid->addWidget( lab, 4, 0 ); dumpBtn = new KPushButton( gb ); dumpBtn->setGuiItem( KGuiItem(i18n("Dump"), icon->loadIconSet("filesave", KIcon::Small) ) ); - grid->addWidget( dumpBtn, 2, 1 ); + grid->addWidget( dumpBtn, 4, 1 ); vb->addWidget( gb ); vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Ignored, QSizePolicy::Ignored ) ); @@ -1039,6 +1133,8 @@ void DvbConfigDialog::satNumberChanged( int value, int devNum ) rotor1[devNum]->setEnabled( value > 1 ); rotor2[devNum]->setEnabled( value > 2 ); rotor3[devNum]->setEnabled( value > 3 ); + + secMini[devNum]->setEnabled( value==2 ); } @@ -1103,6 +1199,9 @@ void DvbConfigDialog::accept() switch (dvbConfig->devList.at(i)->type) { case FE_QPSK: { dvbConfig->devList.at(i)->numLnb = satNumber[i]->value(); + dvbConfig->devList.at(i)->secMini = secMini[i]->isChecked(); + dvbConfig->devList.at(i)->secTwice = secTwice[i]->isChecked(); + dvbConfig->devList.at(i)->doS2 = doS2[i]->isChecked(); if ( dvbConfig->devList.at(i)->lnb[3].rotorType==0 ) { dvbConfig->devList.at(i)->lnb[3].source.clear(); dvbConfig->devList.at(i)->lnb[3].source.append(sat3[i]->currentText()); @@ -1140,6 +1239,7 @@ void DvbConfigDialog::accept() } dvbConfig->devList.at(i)->source = s; dvbConfig->devList.at(i)->tuningTimeout = timeoutSpin.at(i)->value(); + dvbConfig->devList.at(i)->priority = priority.at(i)->value(); } dvbConfig->recordDir = recordDirLe->text(); @@ -1157,6 +1257,8 @@ void DvbConfigDialog::accept() dvbConfig->broadcastAddress = broadcastLe->text().stripWhiteSpace(); dvbConfig->broadcastPort = bportSpin->value(); dvbConfig->senderPort = sportSpin->value(); + dvbConfig->probeMfe = probeMfe->isChecked(); + dvbConfig->ringBufSize = ringBufSize->value(); dvbConfig->saveConfig(); done( Accepted ); } @@ -1403,22 +1505,24 @@ RotorConfig::RotorConfig( Device *d, DVBconfig *c, int lnb, QWidget *parent ) : vb->addWidget( resetBtn ); vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Fixed, QSizePolicy::Fixed ) ); - grid = new QGridLayout( 0, 1, 1 ); - lab = new QLabel( i18n("13V rotor speed:"), page ); - grid->addWidget( lab, 0, 0 ); - speed13 = new QLineEdit( page ); - speed13->setText( QString().setNum( dev->lnb[lnbNum].speed13v ) ); - grid->addWidget( speed13, 0, 1 ); - lab = new QLabel( i18n("sec./ °"), page ); - grid->addWidget( lab, 0, 2 ); - lab = new QLabel( i18n("18V rotor speed:"), page ); - grid->addWidget( lab, 1, 0 ); - speed18 = new QLineEdit( page ); - speed18->setText( QString().setNum( dev->lnb[lnbNum].speed18v ) ); - grid->addWidget( speed18, 1, 1 ); - lab = new QLabel( i18n("sec./ °"), page ); - grid->addWidget( lab, 1, 2 ); - vb->addLayout( grid ); + if ( dev->lnb[lnbNum].rotorType!=3 ) { + grid = new QGridLayout( 0, 1, 1 ); + lab = new QLabel( i18n("13V rotor speed:"), page ); + grid->addWidget( lab, 0, 0 ); + speed13 = new QLineEdit( page ); + speed13->setText( QString().setNum( dev->lnb[lnbNum].speed13v ) ); + grid->addWidget( speed13, 0, 1 ); + lab = new QLabel( i18n("sec./ °"), page ); + grid->addWidget( lab, 0, 2 ); + lab = new QLabel( i18n("18V rotor speed:"), page ); + grid->addWidget( lab, 1, 0 ); + speed18 = new QLineEdit( page ); + speed18->setText( QString().setNum( dev->lnb[lnbNum].speed18v ) ); + grid->addWidget( speed18, 1, 1 ); + lab = new QLabel( i18n("sec./ °"), page ); + grid->addWidget( lab, 1, 2 ); + vb->addLayout( grid ); + } vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Ignored, QSizePolicy::Ignored ) ); @@ -1462,8 +1566,14 @@ void RotorConfig::accept() { QListViewItem *it; - dev->lnb[lnbNum].speed18v = speed18->text().toDouble(); - dev->lnb[lnbNum].speed13v = speed13->text().toDouble(); + if ( dev->lnb[lnbNum].rotorType!=3 ) { + dev->lnb[lnbNum].speed18v = speed18->text().toDouble(); + dev->lnb[lnbNum].speed13v = speed13->text().toDouble(); + } + else { + dev->lnb[lnbNum].speed18v = 0; + dev->lnb[lnbNum].speed13v = 0; + } dev->lnb[lnbNum].source.clear(); dev->lnb[lnbNum].position.clear(); for ( it=listView->firstChild(); it; it=it->nextSibling() ) { diff --git a/kaffeine/src/input/dvb/dvbconfig.h b/kaffeine/src/input/dvb/dvbconfig.h index f52b9cc..04f2bf1 100644 --- a/kaffeine/src/input/dvb/dvbconfig.h +++ b/kaffeine/src/input/dvb/dvbconfig.h @@ -28,6 +28,7 @@ #include <qtoolbutton.h> #include <qbuttongroup.h> #include <qlistview.h> +#include <qcheckbox.h> #include <kdialogbase.h> #include <kpushbutton.h> @@ -37,6 +38,8 @@ #include <linux/dvb/frontend.h> +#define MAX_DEVICES 8 + using namespace KIO; class MSpinBox : public QSpinBox @@ -70,6 +73,21 @@ private: +class MCAMButton : public QPushButton +{ + Q_OBJECT +public: + MCAMButton( QWidget *parent, int devNum ); +private slots: + void isClicked(); +signals: + void clicked( int devnum ); +private: + int deviceNumber; +}; + + + class MComboBox : public QComboBox { Q_OBJECT @@ -116,6 +134,12 @@ public: bool canAutoscan; int tuningTimeout; double usalsLatitude, usalsLongitude; + bool hasCAM; + int camMaxService; + int secMini; + int secTwice; + int priority; + int doS2; }; @@ -138,6 +162,7 @@ public: DVBconfig( const QString &dvbConf ); ~DVBconfig(); + void readFirst(); void readConfig(); void saveConfig(); int readDvbChanOrder(); @@ -168,6 +193,8 @@ public: QValueList<int> splitSizes; QString defaultCharset; double usalsLatitude, usalsLongitude; + int probeMfe; + int ringBufSize; private: @@ -183,6 +210,7 @@ private slots: class KaffeineDvbPlugin; +class DvbPanel; class DvbConfigDialog : public KDialogBase { @@ -190,34 +218,39 @@ class DvbConfigDialog : public KDialogBase public: - DvbConfigDialog( DVBconfig *dc, QWidget *parent, KaffeineDvbPlugin *p ); + DvbConfigDialog( DvbPanel *pan, DVBconfig *dc, QWidget *parent, KaffeineDvbPlugin *p ); ~DvbConfigDialog(); void setSource( QComboBox *box, QString s ); QLineEdit *recordDirLe, *shiftDirLe, *broadcastLe, *filenameFormatLe; QSpinBox *beginSpin, *endSpin, *instantDurationSpin, *bportSpin, *sportSpin, *sizeFileSpin; - MSpinBox *satNumber[8]; - QComboBox *sat0[8]; - QComboBox *sat1[8]; - QComboBox *sat2[8]; - QComboBox *sat3[8]; - MPushButton *src0[8]; - MPushButton *src1[8]; - MPushButton *src2[8]; - MPushButton *src3[8]; - MComboBox *rotor0[8]; - MComboBox *rotor1[8]; - MComboBox *rotor2[8]; - MComboBox *rotor3[8]; - MPushButton *lnb0[8]; - MPushButton *lnb1[8]; - MPushButton *lnb2[8]; - MPushButton *lnb3[8]; + MSpinBox *satNumber[MAX_DEVICES]; + QCheckBox *secMini[MAX_DEVICES], *secTwice[MAX_DEVICES]; + QCheckBox *doS2[MAX_DEVICES]; + QComboBox *sat0[MAX_DEVICES]; + QComboBox *sat1[MAX_DEVICES]; + QComboBox *sat2[MAX_DEVICES]; + QComboBox *sat3[MAX_DEVICES]; + MPushButton *src0[MAX_DEVICES]; + MPushButton *src1[MAX_DEVICES]; + MPushButton *src2[MAX_DEVICES]; + MPushButton *src3[MAX_DEVICES]; + MComboBox *rotor0[MAX_DEVICES]; + MComboBox *rotor1[MAX_DEVICES]; + MComboBox *rotor2[MAX_DEVICES]; + MComboBox *rotor3[MAX_DEVICES]; + MPushButton *lnb0[MAX_DEVICES]; + MPushButton *lnb1[MAX_DEVICES]; + MPushButton *lnb2[MAX_DEVICES]; + MPushButton *lnb3[MAX_DEVICES]; KPushButton *updateBtn, *dumpBtn; QToolButton *recordDirBtn, *shiftDirBtn, *helpNameBtn; DVBconfig *dvbConfig; QComboBox *charsetComb; QPtrList<QSpinBox> timeoutSpin; + QPtrList<QSpinBox> priority; + QCheckBox *probeMfe; + QSpinBox *ringBufSize; private slots: diff --git a/kaffeine/src/input/dvb/dvbout.cpp b/kaffeine/src/input/dvb/dvbout.cpp index 0ede057..c398707 100644 --- a/kaffeine/src/input/dvb/dvbout.cpp +++ b/kaffeine/src/input/dvb/dvbout.cpp @@ -136,19 +136,23 @@ void DVBout::writePmt() tspmt[0x0a] = 0xc1; // section # and last section # tspmt[0x0b] = tspmt[0x0c] = 0x00; - // PCR PID - tspmt[0x0d] = channel.vpid>>8; tspmt[0x0e] = channel.vpid&0xff; + if ( channel.vpid ) { + // PCR PID + tspmt[0x0d] = channel.vpid>>8; tspmt[0x0e] = channel.vpid&0xff; + } + else if ( channel.napid ) + tspmt[0x0d] = channel.apid[0].pid>>8; tspmt[0x0e] = channel.apid[0].pid&0xff; // program_info_length == 0 tspmt[0x0f] = 0xf0; tspmt[0x10] = 0x00; - // Program Map / Video PID - tspmt[0x11] = channel.vType; // video stream type - tspmt[0x12] = channel.vpid>>8; tspmt[0x13] = channel.vpid&0xff; - tspmt[0x14] = 0xf0; tspmt[0x15] = 0x09; // es info length - // useless info - tspmt[0x16] = 0x07; tspmt[0x17] = 0x04; tspmt[0x18] = 0x08; tspmt[0x19] = 0x80; - tspmt[0x1a] = 0x24; tspmt[0x1b] = 0x02; tspmt[0x1c] = 0x11; tspmt[0x1d] = 0x01; - tspmt[0x1e] = 0xfe; - off = 0x1e; + if ( channel.vpid ) { + // Program Map / Video PID + tspmt[0x11] = channel.vType; // video stream type + tspmt[0x12] = channel.vpid>>8; tspmt[0x13] = channel.vpid&0xff; + tspmt[0x14] = 0xf0; tspmt[0x15] = 0x00; // es info length + off = 0x15; + } + else + off = 0x10; // audio pids i = 0; for ( i=0; i<channel.napid && i<MAX_AUDIO; i++ ) { @@ -258,20 +262,19 @@ bool DVBout::doPause( const QString &name ) // called from dvbstream::run() liveFile.writeBlock( (char*)tspmt, TS_SIZE ); mutex.lock(); haveLive = false; - mutex.unlock(); - if ( !wait(100) ) { + if ( !wait(1000) ) { terminate(); wait(); } - mutex.lock(); - haveLive = true; if ( close( fdPipe )<0 ) perror("close out pipe: "); else fprintf(stderr,"out pipe closed\n"); fdPipe = 0; - mutex.unlock(); + if ( wDist>0 ) + liveFile.writeBlock( (char*)(wBuf+(wRead*TS_SIZE*NTS)), TS_SIZE*NTS*wDist ); timeShifting = true; + mutex.unlock(); //emit shifting( timeShifting ); } return true; @@ -286,7 +289,7 @@ void DVBout::setPatPmt() -bool DVBout::goLive( const QString &name ) +bool DVBout::goLive( const QString &name, int ringBufSize ) { if ( fdPipe ) return false; @@ -299,7 +302,8 @@ bool DVBout::goLive( const QString &name ) writePmt(); if ( !pids.contains(8192) ) patpmt = wpatpmt = true; - wBuf = new unsigned char[TS_SIZE*NTS*100]; + wbufSize = ringBufSize*1024*1024/(TS_SIZE*NTS); + wBuf = new unsigned char[TS_SIZE*NTS*wbufSize]; if ( !wBuf ) fprintf( stderr, "\nNO WBUF !!!\n\n" ); wRead = wWrite = wDist = 0; start(); @@ -326,7 +330,7 @@ void DVBout::stopLive() emit shifting( timeShifting ); } mutex.unlock(); - if ( !wait(500) ) { + if ( !wait(1000) ) { terminate(); wait(); } @@ -469,14 +473,16 @@ void DVBout::process( unsigned char *buf, int size ) beginLive = !beginLive; start(); } - if ( wDist<95 ) { + if ( wDist<wbufSize ) { memcpy( wBuf+(wWrite*TS_SIZE*NTS), thBuf, TS_SIZE*NTS ); wpatpmt = patpmt; ++wDist; ++wWrite; - if ( wWrite>99 ) + if ( wWrite==wbufSize ) wWrite = 0; - //fprintf(stderr,"WDIST = %d\n",wDist); + } + else { + fprintf(stderr,"Live ringbuffer full!! (%d)\n",wDist); } } else if ( timeShifting ) { @@ -531,7 +537,7 @@ void DVBout::run() { if ( haveLive && fdPipe ) { while ( haveLive && fdPipe ) { - if ( wDist>0 ) { + if ( wDist>5 ) { if ( wpatpmt ) { write( fdPipe, tspat, TS_SIZE ); write( fdPipe, tspmt, TS_SIZE ); @@ -540,11 +546,12 @@ void DVBout::run() write( fdPipe, wBuf+(wRead*TS_SIZE*NTS), TS_SIZE*NTS ); --wDist; ++wRead; - if ( wRead>99 ) + if ( wRead==wbufSize ) wRead = 0; } - else + else { usleep( 100 ); + } } return; } diff --git a/kaffeine/src/input/dvb/dvbout.h b/kaffeine/src/input/dvb/dvbout.h index bc97b47..a037c7d 100644 --- a/kaffeine/src/input/dvb/dvbout.h +++ b/kaffeine/src/input/dvb/dvbout.h @@ -44,7 +44,7 @@ public: DVBout( ChannelDesc chan, int anum, int tnum, KaffeineDvbPlugin *p ); ~DVBout(); void process( unsigned char *buf, int size ); - bool goLive( const QString &name ); + bool goLive( const QString &name, int ringBufSize ); void preStopLive(); void stopLive(); bool goBroadcast( Ts2Rtp *r ); @@ -102,6 +102,7 @@ private: int fileNumber; QString fileName; long long int fileMaxSize; + int wbufSize; signals: diff --git a/kaffeine/src/input/dvb/dvbpanel.cpp b/kaffeine/src/input/dvb/dvbpanel.cpp index 4d70760..1b62aec 100644 --- a/kaffeine/src/input/dvb/dvbpanel.cpp +++ b/kaffeine/src/input/dvb/dvbpanel.cpp @@ -45,7 +45,6 @@ #include <kxmlguifactory.h> #include <kparts/componentfactory.h> -#include "kaffeineinput.h" #include "kaffeinedvbplugin.h" #include "dvbpanel.h" #include "channeldesc.h" @@ -56,6 +55,12 @@ #define CHANICONSIZE 28 +#define MODE_FREE 0 +#define MODE_LIVE 100 +#define MODE_BROADCAST 200 +#define MODE_RECORD 300 +#define MODE_CANTDO 400 + DIconViewItem::DIconViewItem( DvbPanel *pan, QIconView *parent, const QString &text, const QPixmap &icon ) @@ -1091,7 +1096,7 @@ void DvbPanel::setConfig() void DvbPanel::showConfigDialog() { - int ret; + int i, ret; loop: if ( !dvbConfig->haveData() ) { @@ -1104,7 +1109,9 @@ loop: return; } - DvbConfigDialog dlg( dvbConfig, mainWidget, plug ); + for ( i=0; i<(int)dvb.count(); i++ ) + dvb.at(i)->probeCam(); + DvbConfigDialog dlg( this, dvbConfig, mainWidget, plug ); connect( dlg.dumpBtn, SIGNAL(clicked()), this, SLOT(dumpEvents()) ); ret = dlg.exec(); disconnect( dlg.dumpBtn, SIGNAL(clicked()), this, SLOT(dumpEvents()) ); @@ -1112,6 +1119,14 @@ loop: return; rtp->setSocket( dvbConfig->broadcastAddress, dvbConfig->broadcastPort, dvbConfig->senderPort ); cleaner->setPaths( dvbConfig->shiftDir, dvbConfig->recordDir ); + fillChannelList(); +} + + + +void DvbPanel::camClicked( int devNum ) +{ + dvb.at(devNum)->showCamDialog(); } @@ -1124,6 +1139,8 @@ QPtrList<Transponder> DvbPanel::getSourcesStatus() Transponder t; for ( i=0; i<(int)dvb.count(); i++ ) { + if ( !dvb.at(i)->getPriority() ) // priority==0==don't use + continue; list = dvb.at(i)->getSources(); for ( j=0; j<(int)list.count(); j++ ) { if ( dvb.at(i)->hasRec() || dvb.at(i)->hasBroadcast() ) @@ -1176,7 +1193,7 @@ void DvbPanel::fillChannelList( ChannelDesc *ch ) } else if ( currentCategory!="All" && chan->category!=currentCategory ) continue; - it = new KListViewItem( channelsCb, QString().sprintf("%04d", chan->num), chan->name, chan->tp.source ); + it = new KListViewItem( channelsCb, QString().sprintf("%05d", chan->num), chan->name, chan->tp.source ); if ( ch && ch==chan ) visible = it; it->setDragEnabled( true ); @@ -1211,15 +1228,15 @@ void DvbPanel::fillChannelList( ChannelDesc *ch ) DvbStream* DvbPanel::getWorkingDvb( int mode, ChannelDesc *chan ) { int i, ret; - QValueList<int> working; // notTuned=0, hasLive=1, hasBroadcast=2, hasRec=3, can'tDoChannel=4 + QValueList<int> working; // free=0, hasLive=100, hasBroadcast=200, hasRec=300, can'tDoChannel=400 for ( i=0; i<(int)dvb.count(); i++ ) - working.append( 0 ); + working.append( 100-dvb.at(i)->getPriority() ); // fill in working status for ( i=0; i<(int)dvb.count(); i++ ) { - if ( !dvb.at(i)->canSource( chan ) ) { - working[i] = 4; + if ( !dvb.at(i)->canSource( chan ) || working[i]==100 ) { + working[i] = MODE_CANTDO; continue; } if ( dvb.at(i)->isTuned() ) { @@ -1227,14 +1244,18 @@ DvbStream* DvbPanel::getWorkingDvb( int mode, ChannelDesc *chan ) return dvb.at(i); // use that one since it's already tuned on the good mplex } else if ( dvb.at(i)->hasRec() ) - working[i] = 3; + working[i] += MODE_RECORD; else if ( dvb.at(i)->hasBroadcast() ) - working[i] = 2; - else - working[i] = 1; + working[i] += MODE_BROADCAST; + else { + if ( mode==MODE_LIVE ) + working[i] += MODE_FREE; + else + working[i] += MODE_LIVE; + } } else - working[i] = 0; + working[i] += MODE_FREE; } ret = 0; // search for least working card @@ -1272,7 +1293,7 @@ void DvbPanel::setBroadcast() return; } - d = getWorkingDvb( 2, list.at(0) ); + d = getWorkingDvb( MODE_BROADCAST, list.at(0) ); if ( d ) ret = d->canStartBroadcast( live, list.at(0) ); @@ -1316,7 +1337,7 @@ void DvbPanel::checkTimers() } if ( !chan ) continue; - d = getWorkingDvb( 3, chan ); + d = getWorkingDvb( MODE_RECORD, chan ); live = false; if ( d ) ret = d->canStartTimer( live, chan ); @@ -1826,7 +1847,7 @@ void DvbPanel::playLastChannel() QTimer::singleShot( 2000, this, SLOT(playLastChannel()) ); return; } - d = getWorkingDvb( 2, list.at(0) ); + d = getWorkingDvb( MODE_BROADCAST, list.at(0) ); if ( d ) ret = d->canStartBroadcast( live, list.at(0) ); else @@ -1880,7 +1901,7 @@ void DvbPanel::next() QListViewItem* nextItem; - QListViewItem* playingItem = channelsCb->findItem( QString().sprintf("%04d", dvbConfig->lastChannel), 0 ); + QListViewItem* playingItem = channelsCb->findItem( QString().sprintf("%05d", dvbConfig->lastChannel), 0 ); if ( !playingItem == 0 ) // yes, it's in the current category { @@ -1906,7 +1927,7 @@ void DvbPanel::previous() QListViewItem* prevItem; - QListViewItem* playingItem = channelsCb->findItem( QString().sprintf("%04d", dvbConfig->lastChannel), 0 ); + QListViewItem* playingItem = channelsCb->findItem( QString().sprintf("%05d", dvbConfig->lastChannel), 0 ); if ( !playingItem == 0 ) // yes, it's in the current category { @@ -1927,19 +1948,14 @@ void DvbPanel::previous() void DvbPanel::dvbZap( ChannelDesc *chan ) { int i; - DvbStream *d=0; + DvbStream *d; if ( currentFifo.isEmpty() || isTuning ) return; isTuning = true; emit setTimeShiftFilename( "" ); - for ( i=0; i<(int)dvb.count(); i++ ) { - if ( dvb.at(i)->getCurrentTransponder()==chan->tp ) { - d = dvb.at(i); - break; - } - } + d = getWorkingDvb( MODE_LIVE, chan ); for ( i=0; i<(int)dvb.count(); i++ ) { if ( dvb.at(i)->hasLive() ) { dvb.at(i)->preStopLive(); @@ -1973,40 +1989,20 @@ void DvbPanel::finalZap( DvbStream *d, ChannelDesc *chan ) { QString s, t; int i; - DvbStream *d1=d, *d2=0; emit setCurrentPlugin( this ); fprintf( stderr, "Tuning to: %s / autocount: %lu\n", chan->name.latin1(), autocount ); QTime tm; tm.start(); - if ( !d1 ) { - for ( i=0; i<(int)dvb.count(); i++ ) { - if ( !dvb.at(i)->canSource( chan ) ) - continue; - if ( dvb.at(i)->isTuned() ) { - if ( dvb.at(i)->getCurrentTransponder()==chan->tp ) { - d1 = dvb.at(i); - break; - } - else d2 = dvb.at(i); - } - else { - d1 = dvb.at(i); - break; - } - } - if ( !d1 && d2 ) - d1 = d2; - } - if ( !d1 ) { + if ( !d ) { emit dvbStop(); isTuning = false; return; } - int ret = d1->goLive( chan, currentFifo ); + int ret = d->goLive( chan, currentFifo, dvbConfig->ringBufSize ); switch ( ret ) { case DvbStream::ErrIsRecording : @@ -2045,7 +2041,7 @@ void DvbPanel::finalZap( DvbStream *d, ChannelDesc *chan ) resetSearch(); } - if ( d1->liveIsRecording() ) + if ( d->liveIsRecording() ) recordBtn->setOn( true ); else recordBtn->setOn( false ); @@ -2255,6 +2251,8 @@ bool DvbPanel::getChannelList() case 67 : chan->tp.coderateH = FEC_6_7; break; case 78 : chan->tp.coderateH = FEC_7_8; break; case 89 : chan->tp.coderateH = FEC_8_9; break; + case 35 : chan->tp.coderateH = FEC_3_5; break; + case 910 : chan->tp.coderateH = FEC_9_10; break; case -1 : chan->tp.coderateH = FEC_AUTO; } s = s.right( s.length()-pos-1 ); @@ -2275,6 +2273,9 @@ bool DvbPanel::getChannelList() case 256 : chan->tp.modulation = QAM_256; break; case 108 : chan->tp.modulation = VSB_8; break; case 116 : chan->tp.modulation = VSB_16; break; + case 1000 : chan->tp.modulation = PSK_8; break; + case 1001 : chan->tp.modulation = APSK_16; break; + case 1003 : chan->tp.modulation = DQPSK; break; case -1 : chan->tp.modulation = QAM_AUTO; } s = s.right( s.length()-pos-1 ); @@ -2289,6 +2290,8 @@ bool DvbPanel::getChannelList() case 67 : chan->tp.coderateL = FEC_6_7; break; case 78 : chan->tp.coderateL = FEC_7_8; break; case 89 : chan->tp.coderateL = FEC_8_9; break; + case 35 : chan->tp.coderateH = FEC_3_5; break; + case 910 : chan->tp.coderateH = FEC_9_10; break; case -1 : chan->tp.coderateL = FEC_AUTO; } s = s.right( s.length()-pos-1 ); @@ -2356,6 +2359,17 @@ bool DvbPanel::getChannelList() s = s.right( s.length()-pos-1 ); pos = s.find("|"); chan->tp.nid = s.left(pos).toUShort(); + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + switch ( s.left(pos).toInt() ) { + case 20 : chan->tp.rolloff = ROLLOFF_20; break; + case 25 : chan->tp.rolloff = ROLLOFF_25; break; + case 35 : chan->tp.rolloff = ROLLOFF_35; break; + case -1 : chan->tp.rolloff = ROLLOFF_AUTO; + } + s = s.right( s.length()-pos-1 ); + pos = s.find("|"); + chan->tp.S2 = s.left(pos).toInt(); if ( chan->tp.source.isEmpty() ) { delete chan; @@ -2363,7 +2377,7 @@ bool DvbPanel::getChannelList() } chan->pix.load( dvbConfig->dvbConfigIconsDir+chan->name ); - it = new KListViewItem( channelsCb, QString().sprintf("%04d", chan->num), chan->name, chan->tp.source ); + it = new KListViewItem( channelsCb, QString().sprintf("%05d", chan->num), chan->name, chan->tp.source ); it->setDragEnabled( true ); if ( !chan->pix.isNull() ) it->setPixmap( 1, chan->pix ); @@ -2467,6 +2481,8 @@ bool DvbPanel::saveChannelList() case FEC_6_7 : tt<< "67|"; break; case FEC_7_8 : tt<< "78|"; break; case FEC_8_9 : tt<< "89|"; break; + case FEC_3_5 : tt<< "35|"; break; + case FEC_9_10 : tt<< "910|"; break; case FEC_AUTO : tt<< "-1|"; } switch ( chan->tp.inversion ) { @@ -2483,6 +2499,9 @@ bool DvbPanel::saveChannelList() case QAM_256 : tt<< "256|"; break; case VSB_8 : tt<< "108|"; break; case VSB_16 : tt<< "116|"; break; + case PSK_8 : tt<< "1000|"; break; + case APSK_16 : tt<< "1001|"; break; + case DQPSK : tt<< "1003|"; break; case QAM_AUTO : tt<< "-1|"; } switch ( chan->tp.coderateL ) { @@ -2495,6 +2514,8 @@ bool DvbPanel::saveChannelList() case FEC_6_7 : tt<< "67|"; break; case FEC_7_8 : tt<< "78|"; break; case FEC_8_9 : tt<< "89|"; break; + case FEC_3_5 : tt<< "35|"; break; + case FEC_9_10 : tt<< "910|"; break; case FEC_AUTO : tt<< "-1|"; } switch ( chan->tp.bandwidth ) { @@ -2533,7 +2554,15 @@ bool DvbPanel::saveChannelList() } tt<< "|"; tt<< chan->category+"|"; - tt<< s.setNum(chan->tp.nid)+"|\n"; + tt<< s.setNum(chan->tp.nid)+"|"; + switch ( chan->tp.rolloff ) { + case ROLLOFF_20 : tt<< "20|"; break; + case ROLLOFF_25 : tt<< "25|"; break; + case ROLLOFF_35 : tt<< "35|"; break; + case ROLLOFF_AUTO : tt<< "-1|"; + } + tt<< s.setNum(chan->tp.S2)+"|"; + tt<< "\n"; } ret = true; f.close(); diff --git a/kaffeine/src/input/dvb/dvbpanel.h b/kaffeine/src/input/dvb/dvbpanel.h index 5545040..444e641 100644 --- a/kaffeine/src/input/dvb/dvbpanel.h +++ b/kaffeine/src/input/dvb/dvbpanel.h @@ -42,13 +42,13 @@ #include "ts2rtp.h" #include "cleaner.h" #include "dvbevents.h" +#include "kaffeineinput.h" class ChannelDesc; class DvbStream; class DvbPanel; -class KaffeineInput; class KaffeineDvbPlugin; @@ -153,6 +153,7 @@ public slots: void dvbNewTimer( QString name, QString channel, QString datetime, QString duration ); int getSNR( int device ); void diskStatus(); + void camClicked( int devNum ); private: diff --git a/kaffeine/src/input/dvb/dvbsi.cpp b/kaffeine/src/input/dvb/dvbsi.cpp index 395d796..db29091 100644 --- a/kaffeine/src/input/dvb/dvbsi.cpp +++ b/kaffeine/src/input/dvb/dvbsi.cpp @@ -2,6 +2,7 @@ * dvbsi.cpp * * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr> + * Copyright (C) 2008 Devin Heitmueller <devin.heitmueller@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,7 +31,22 @@ #define TIMER_EVENT_SCAN_END 100 +// These values are taken from ATSC A/65C Sec 5 +#define PSIP_BASE_PID 0x1ffb +// This shouldn't be necessary, but at least the HVR-950 doesn't seem to +// find them in the time specified in the spec (needs more investigation) +#define CYCLE_TIME_FUDGEFACTOR 1000 + +// These values are taken from ATSC A/65C Sec 7.1 +// (all values in ms) +#define PSIP_MAX_CYCLE_TIME_MGT 150 + CYCLE_TIME_FUDGEFACTOR +#define PSIP_MAX_CYCLE_TIME_VCT 400 + CYCLE_TIME_FUDGEFACTOR + +// These values are taken from ATSC A/65C Sec 4.1 +#define PSIP_TABLE_TYPE_MGT 0xc7 +#define PSIP_TABLE_TYPE_TVCT 0xc8 +#define PSIP_TABLE_TYPE_CVCT 0xc9 NitSection::NitSection( QPtrList<Transponder> *tp, bool *end, bool *ok, int anum, int tnum ) : KaffeineDVBsection( anum, tnum ) { @@ -158,6 +174,9 @@ bool NitSection::tableNIT( unsigned char* buf ) fprintf(stderr," Found frequency list.\n"); freqListDesc( buf, trans ); break; + case 0x79 : + S2satelliteDesc( buf, trans ); + break; default : break; } @@ -211,18 +230,53 @@ void NitSection::satelliteDesc( unsigned char* buf, Transponder *trans ) trans->pol = 'v'; else trans->pol = 'h'; + switch ( getBits(buf,70,2) ) { + case 0 : trans->modulation = QAM_AUTO; break; + case 1 : trans->modulation = QPSK; break; + case 2 : trans->modulation = PSK_8; break; + case 3 : trans->modulation = QAM_16; break; + } s = t.setNum( getBits(buf,72,28), 16 ); trans->sr = s.toInt(); trans->sr /=10; switch ( getBits(buf,100,4) ) { + case 0 : trans->coderateH = FEC_AUTO; break; case 1 : trans->coderateH = FEC_1_2; break; case 2 : trans->coderateH = FEC_2_3; break; case 3 : trans->coderateH = FEC_3_4; break; case 4 : trans->coderateH = FEC_5_6; break; case 5 : trans->coderateH = FEC_7_8; break; case 6 : trans->coderateH = FEC_8_9; break; - case 7 : trans->coderateH = FEC_NONE; break; + case 7 : trans->coderateH = FEC_3_5; break; + case 8 : trans->coderateH = FEC_4_5; break; + case 9 : trans->coderateH = FEC_9_10; break; + case 15 : trans->coderateH = FEC_NONE; break; } + if ( getBits(buf,69,1) ) { + fprintf(stderr,"!!!!!!!!!!!!!!!!!! Found S2 MODULATION SYSTEM !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); + trans->S2 = 1; + switch ( getBits(buf,67,2) ) { + case 0 : trans->rolloff = ROLLOFF_35; break; + case 1 : trans->rolloff = ROLLOFF_25; break; + case 2 : trans->rolloff = ROLLOFF_20; break; + } + } +} + + + +void NitSection::S2satelliteDesc( unsigned char* buf, Transponder *trans ) +{ + fprintf(stderr,"!!!!!!!!!!!!!!!!!! Found S2 DESCRIPTOR !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); + int scrambling_sequence_selector = getBits(buf,16,1); + int multiple_input_stream_flag = getBits(buf,17,1); + int backwards_compatibility_indicator = getBits(buf,18,1); + int scrambling_sequence_index = 0; + if ( scrambling_sequence_selector ) + scrambling_sequence_index = getBits(buf,30,18); + int input_stream_identifier = 0; + if ( multiple_input_stream_flag ) + input_stream_identifier = getBits(buf,48,8); } @@ -246,13 +300,17 @@ void NitSection::cableDesc( unsigned char* buf, Transponder *trans ) trans->sr = s.toInt(); trans->sr /=10; switch ( getBits(buf,100,4) ) { + case 0 : trans->coderateH = FEC_AUTO; break; case 1 : trans->coderateH = FEC_1_2; break; case 2 : trans->coderateH = FEC_2_3; break; case 3 : trans->coderateH = FEC_3_4; break; case 4 : trans->coderateH = FEC_5_6; break; case 5 : trans->coderateH = FEC_7_8; break; case 6 : trans->coderateH = FEC_8_9; break; - case 7 : trans->coderateH = FEC_NONE; break; + case 7 : trans->coderateH = FEC_3_5; break; + case 8 : trans->coderateH = FEC_4_5; break; + case 9 : trans->coderateH = FEC_9_10; break; + case 15 : trans->coderateH = FEC_NONE; break; } } @@ -456,6 +514,7 @@ bool DVBsi::tablePMT( unsigned char* buf ) while ( length>4 ) { audio=ac3=false; + lang=""; type = getBits(buf,0,8); pid = getBits(buf,11,13); if ( type==1/*mpeg1*/ || type==2/*mpeg2*/ || type==16/*mpeg4*/ || type==27/*h264*/ ) { @@ -466,6 +525,11 @@ bool DVBsi::tablePMT( unsigned char* buf ) if ( type==3 || type==4 ) { audio = true; } + if (type == 0x81) { + // AC3 was added in ATSC A/52B (See A3.1 "Stream Type") + audio = true; + ac3 = true; + } loop = getBits(buf,28,12); buf +=5; length -=(5+loop); @@ -499,6 +563,7 @@ bool DVBsi::tablePMT( unsigned char* buf ) } break; case 0x6a : + case 0x81 : audio = true; ac3 = true; break; @@ -637,7 +702,204 @@ bool DVBsi::getSection( int pid, int tid, int timeout, int sid ) return true; } +bool DVBsi::parseMGT( int pid, int tid, int timeout, int sid ) +{ + unsigned char buf[4096]; + int n=0; + int skip=0; + bool vct_found = false; + + fprintf(stderr, "parseMGT called for 0x%02x 0x%02x\n", pid, tid); + if ( !setFilter( pid, tid, timeout ) ) + return false; + + if ( poll(pf,1,timeout)>0 ){ + if ( pf[0].revents & POLLIN ){ + n = read( fdDemux, buf, 4096 ); + skip = 0; + } + else + skip++; + } + else + skip++; + + if ( skip || n<4 ) { + fprintf(stderr,"\nInvalid section length or timeout: pid=%d\n\n", pid); + stopFilter(); + return false; + } + + // Parse the Master Guide Table Section + unsigned int protocol_version = getBits(buf,64,8); + unsigned int tables_defined = getBits(buf,72,16); + fprintf(stderr, "protocol_version = %d\n", protocol_version); + fprintf(stderr, "tables_defined = %d\n", tables_defined); + + // Now let's go through the table entries.... + unsigned char *t_entry = &buf[88/8]; + for (unsigned int t = 0; t < tables_defined; t++) { + unsigned int table_type; + unsigned int table_pid; + unsigned int table_version_number; + unsigned int table_number_bytes; + unsigned int table_number_des_length; + table_type = getBits(t_entry, 0, 16); + table_pid = getBits(t_entry, 19, 13); + table_version_number = getBits(t_entry, 35, 5); + table_number_bytes = getBits(t_entry, 40, 32); + table_number_des_length = getBits(t_entry, 76, 12); + fprintf(stderr, + "MGT entry type=0x%04x pid=0x%04x ver=%d sz=%d\n", + table_type, table_pid, table_version_number, + table_number_bytes); + + if (table_type == 0x0000 || table_type == 0x0001) { + // TVCT table found + vct_table = PSIP_TABLE_TYPE_TVCT; + vct_found = true; + } else if (table_type == 0x0002 || + table_type == 0x0003) { + // CVCT table found + vct_table = PSIP_TABLE_TYPE_CVCT; + vct_found = true; + } + t_entry += (11 + table_number_des_length); + } + + stopFilter(); + return vct_found; +} + +bool DVBsi::parseVCT( int pid, int tid, int timeout, int sid ) +{ + unsigned char buf[4096]; + int n=0; + int skip=0; + + fprintf(stderr, "parseVCT called for 0x%02x 0x%02x\n", pid, tid); + if ( !setFilter( pid, tid, timeout ) ) + return false; + + if ( poll(pf,1,timeout)>0 ){ + if ( pf[0].revents & POLLIN ){ + n = read( fdDemux, buf, 4096 ); + skip = 0; + } + else + skip++; + } + else + skip++; + + if ( skip || n<4 ) { + fprintf(stderr,"\nInvalid section length or timeout: pid=%d\n\n", pid); + stopFilter(); + return false; + } + + // Parse the Virtual Channel Table Section + unsigned int protocol_version = getBits(buf,64,8); + unsigned int num_channels = getBits(buf,72,8); + fprintf(stderr, "protocol_version = %d\n", protocol_version); + fprintf(stderr, "num_channels = %d\n", num_channels); + + // Now let's go through the table entries.... + unsigned char *t_entry = &buf[80/8]; + for (unsigned int t = 0; t < num_channels; t++) { + char short_name[8]; + unsigned int major_channel_num; + unsigned int minor_channel_num; + unsigned int modulation_mode; + unsigned int channel_tsid; + unsigned int program_number; + unsigned int access_controlled; + unsigned int hidden; + unsigned int service_type; + unsigned int source_id; + unsigned int reserved; + unsigned int descriptors_length; + + // Short name + // Yes, I need a real UCS-2 to UTF-8 conversion here... + memset(short_name, 0, sizeof(short_name)); + snprintf(short_name, sizeof(short_name), "%c%c%c%c%c%c%c", + t_entry[1],t_entry[3],t_entry[5],t_entry[7], + t_entry[9],t_entry[11],t_entry[13]); + reserved = getBits(t_entry, 112, 4); + major_channel_num = getBits(t_entry, 116, 10); + minor_channel_num = getBits(t_entry, 126, 10); + modulation_mode = getBits(t_entry, 136, 8); + channel_tsid = getBits(t_entry, 176, 16); + program_number = getBits(t_entry, 192, 16); + access_controlled = getBits(t_entry, 210, 1); + hidden = getBits(t_entry, 211, 1); + service_type = getBits(t_entry, 218, 6); + source_id = getBits(t_entry, 224, 16); + reserved = getBits(t_entry, 240, 6); + descriptors_length = getBits(t_entry, 246, 10); + + fprintf(stderr, "short name=%s\n", short_name); + fprintf(stderr, "reserved=0x%04x\n", reserved); + fprintf(stderr, "major=%d\n", major_channel_num); + fprintf(stderr, "minor=%d\n", minor_channel_num); + fprintf(stderr, "modulation mode=0x%02x\n", modulation_mode); + fprintf(stderr, "channel_tsid=0x%04x\n", channel_tsid); + fprintf(stderr, "program_number=0x%04x\n", program_number); + fprintf(stderr, "access_controlled=0x%01x\n", access_controlled); + fprintf(stderr, "hidden=0x%01x\n", hidden); + fprintf(stderr, "service_type=0x%02x\n", service_type); + fprintf(stderr, "source_id=0x%04x\n", source_id); + fprintf(stderr, "des length=%d\n", descriptors_length); + + ChannelDesc *desc = new ChannelDesc(); + desc->tp.tsid = channel_tsid; + desc->name = QString("%1-%2 %3").arg(major_channel_num).arg(minor_channel_num).arg(short_name); + desc->sid = program_number; + if (access_controlled == 1) + desc->fta = 1; + else + desc->fta = 0; // 0 for free + + // Algorithm taken from ATSC A/65C Sec 4.2 + // However, the algorithm doesn't appear correct, as it + // truncates out data. For example, both 68-1 and 4-1 would + // yield the same one_part_number + desc->num = (major_channel_num << 10) + minor_channel_num; + fprintf(stderr, "channel num=%d\n", desc->num); + + // ATSC A/65C Sec 6.3.1 Table 6.7 + if (service_type == 0x01) { + // Analog television (not supported) + } else if (service_type == 0x02) { + // ATSC Video + desc->type = 1; + } else if (service_type == 0x03) { + // ATSC Audio + desc->type = 2; + } else if (service_type == 0x02) { + // ATSC Data only service (not supported) + } else if (service_type > 0x05 && service_type < 0x3f) { + // Reserved (not supported) + } else { + // Unknown + } + + // Now add the new channel to the list (if supported) + if ((desc->type == 1 || desc->type == 2) && hidden == 0) { + channels.append( desc ); + } else { + fprintf(stderr, "Not adding channel\n"); + delete desc; + } + + // Advance to the next entry + t_entry += (32 + descriptors_length); + } + stopFilter(); + return true; +} void DVBsi::stop() { @@ -701,7 +963,24 @@ void DVBsi::timerEvent( QTimerEvent *e ) } } +// See ATSC standard A/65c for info on PSIP and what all these acronyms are... +bool DVBsi::handle_atsc_transponder() { + // Loop through the MGT to get the list of PIDS for virtual channels + if (parseMGT(PSIP_BASE_PID, PSIP_TABLE_TYPE_MGT, + PSIP_MAX_CYCLE_TIME_MGT) == false) { + // We couldn't find the MGT + fprintf(stderr, "Could not find MGT in stream. Cannot continue\n"); + return false; + }; + // Now look at the TVCT for info on the individual channels found + if (parseVCT(PSIP_BASE_PID, vct_table, + PSIP_MAX_CYCLE_TIME_VCT) == false) { + fprintf(stderr, "Could not parse VCT in stream. Cannot continue\n"); + return false; + } + return true; +} void DVBsi::run() { @@ -744,12 +1023,22 @@ void DVBsi::run() indexChannels = j; fprintf(stderr,"Transponders: %d/%d\n", i+1, transponders.count() ); - if ( scanMode ) { - nitEnded = false; - ns = new NitSection( &transponders, &nitEnded, &ok, adapter, tuner ); //NIT + fprintf(stderr,"scanMode=%d\n", scanMode); + if ( chan.tp.type == FE_ATSC ) { + // Separate out the ATSC scanning so that we + // don't interfere with existing DVB support + if (!handle_atsc_transponder()) + continue; + } + else { + printf("it's dvb %d!\n", chan.tp.type); + if ( scanMode ) { + nitEnded = false; + ns = new NitSection( &transponders, &nitEnded, &ok, adapter, tuner ); //NIT + } + + getSection( 0x11, 0x42 ); //SDT } - if ( !getSection( 0x11, 0x42 ) ) //SDT - continue; if ( !isRunning ) { out(); return; @@ -822,7 +1111,7 @@ void DVBsi::run() } - +// !!!! only there for debugging !!!!!!!!!! bool DVBsi::listChannels() { QString s,t; diff --git a/kaffeine/src/input/dvb/dvbsi.h b/kaffeine/src/input/dvb/dvbsi.h index df1f6e7..1146f85 100644 --- a/kaffeine/src/input/dvb/dvbsi.h +++ b/kaffeine/src/input/dvb/dvbsi.h @@ -36,6 +36,7 @@ public: bool getSection( int pid, int tid, int timeout=5000 ); bool tableNIT( unsigned char* buf ); void satelliteDesc( unsigned char* buf, Transponder *trans ); + void S2satelliteDesc( unsigned char* buf, Transponder *trans ); void cableDesc( unsigned char* buf, Transponder *trans ); void terrestrialDesc( unsigned char* buf, Transponder *trans ); void freqListDesc( unsigned char* buf, Transponder *trans ); @@ -66,6 +67,11 @@ public: bool tablePMT( unsigned char* buf ); void serviceDesc( unsigned char* buf, ChannelDesc *desc ); + // ATSC related methods + virtual bool handle_atsc_transponder(); + virtual bool parseMGT( int pid, int tid, int timeout=5000, int sid=0 ); + virtual bool parseVCT( int pid, int tid, int timeout=5000, int sid=0 ); + QPtrList<ChannelDesc> channels; QPtrList<Transponder> transponders; DvbStream *dvb; @@ -90,6 +96,9 @@ private: int scanMode; NitSection *ns; + /* ATSC related */ + int vct_table; + signals: void end( bool ); diff --git a/kaffeine/src/input/dvb/dvbstream.cpp b/kaffeine/src/input/dvb/dvbstream.cpp index 302c0d0..77bee5c 100644 --- a/kaffeine/src/input/dvb/dvbstream.cpp +++ b/kaffeine/src/input/dvb/dvbstream.cpp @@ -43,6 +43,7 @@ #include <klocale.h> #include <kapplication.h> +#include <kmessagebox.h> #include "dvbstream.h" #include "dvbevents.h" @@ -100,13 +101,23 @@ void DvbStream::probeCam() int ci_type=0; if ( camProbed ) return; - if ( (ci_type=DvbCam::probe( dvbDevice->adapter, 0 ))>0 ) - cam = new DvbCam( dvbDevice->adapter, 0, dvbDevice->tuner, ci_type ); + if ( (ci_type=DvbCam::probe( dvbDevice->adapter, 0 ))>0 ) { + cam = new DvbCam( dvbDevice->adapter, 0, dvbDevice->tuner, ci_type, dvbDevice->camMaxService ); + dvbDevice->hasCAM = true; + } camProbed = true; } +void DvbStream::showCamDialog() +{ + if ( cam ) + dvbDevice->camMaxService = cam->showCamDialog(); +} + + + QStringList DvbStream::getSources( bool all ) { if ( !all ) { @@ -143,6 +154,8 @@ bool DvbStream::canSource( ChannelDesc *chan ) else return false; } + if ( chan->tp.S2 && !dvbDevice->doS2 ) + return false; int i; for ( i=0; i<dvbDevice->numLnb; i++ ) { if ( dvbDevice->lnb[i].source.contains(chan->tp.source) ) @@ -153,6 +166,13 @@ bool DvbStream::canSource( ChannelDesc *chan ) +int DvbStream::getPriority() +{ + return dvbDevice->priority; +} + + + int DvbStream::getSatPos( const QString &src ) { int i; @@ -174,7 +194,7 @@ bool DvbStream::openFe() fprintf(stderr,"openFe: fdFrontend != 0\n"); return false; } - fdFrontend = open( frontendName.ascii(), O_RDWR ); + fdFrontend = open( frontendName.ascii(), O_RDWR /*| O_NONBLOCK*/ ); if ( fdFrontend<0 ) { perror("openFe:"); fdFrontend = 0; @@ -308,7 +328,6 @@ bool DvbStream::tuneDvb( ChannelDesc *chan, bool dvr ) { unsigned long lof=0; int res, hiband=0; - struct dvb_frontend_parameters feparams; struct dvb_frontend_info fe_info; fe_status_t status; unsigned long freq=chan->tp.freq; @@ -317,6 +336,14 @@ bool DvbStream::tuneDvb( ChannelDesc *chan, bool dvr ) int rotorMove = 0; int loop=0, i; + struct dtv_property cmdargs[20]; + struct dtv_properties cmdseq; + int inversion; + int bandwidth; + + if ( chan->tp.S2 && !dvbDevice->doS2 ) + return false; + closeFe(); if ( !openFe() ) return false; @@ -333,18 +360,45 @@ bool DvbStream::tuneDvb( ChannelDesc *chan, bool dvr ) freq*=1000; srate*=1000; + QTime t1 = QTime::currentTime(); + + if ( chan->tp.inversion==INVERSION_AUTO ) { + if ( fe_info.caps & FE_CAN_INVERSION_AUTO ) + inversion = chan->tp.inversion; + else { + fprintf(stderr,"Can NOT inversion_auto\n"); + inversion = INVERSION_OFF; + } + } + else + inversion=chan->tp.inversion; + switch( fe_info.type ) { case FE_OFDM : { + QString s = fe_info.name; + //if ( s.contains("TerraTec/qanu USB2.0 Highspeed DVB-T Receiver") ) // cinergyT2 hack + // freq+=167000; if (freq < 1000000) freq*=1000UL; - feparams.frequency=freq; - feparams.u.ofdm.bandwidth=chan->tp.bandwidth; - feparams.u.ofdm.code_rate_HP=chan->tp.coderateH; - feparams.u.ofdm.code_rate_LP=chan->tp.coderateL; - feparams.u.ofdm.constellation=chan->tp.modulation; - feparams.u.ofdm.transmission_mode=chan->tp.transmission; - feparams.u.ofdm.guard_interval=chan->tp.guard; - feparams.u.ofdm.hierarchy_information=chan->tp.hierarchy; + cmdargs[0].cmd = DTV_DELIVERY_SYSTEM; cmdargs[0].u.data = SYS_DVBT; + cmdargs[1].cmd = DTV_FREQUENCY; cmdargs[1].u.data = freq; + cmdargs[2].cmd = DTV_MODULATION; cmdargs[2].u.data = chan->tp.modulation; + cmdargs[3].cmd = DTV_CODE_RATE_HP; cmdargs[3].u.data = chan->tp.coderateH; + cmdargs[4].cmd = DTV_CODE_RATE_LP; cmdargs[4].u.data = chan->tp.coderateL; + cmdargs[5].cmd = DTV_GUARD_INTERVAL; cmdargs[5].u.data = chan->tp.guard; + cmdargs[6].cmd = DTV_TRANSMISSION_MODE; cmdargs[6].u.data = chan->tp.transmission; + cmdargs[7].cmd = DTV_HIERARCHY; cmdargs[7].u.data = chan->tp.hierarchy; + if ( chan->tp.bandwidth==BANDWIDTH_8_MHZ ) + bandwidth = 8000000; + else if ( chan->tp.bandwidth==BANDWIDTH_7_MHZ ) + bandwidth = 7000000; + else if ( chan->tp.bandwidth==BANDWIDTH_6_MHZ ) + bandwidth = 6000000; + cmdargs[8].cmd = DTV_BANDWIDTH_HZ; cmdargs[8].u.data = bandwidth; + cmdargs[9].cmd = DTV_INVERSION; cmdargs[9].u.data = inversion; + cmdargs[10].cmd = DTV_TUNE; + cmdseq.num = 11; + cmdseq.props = cmdargs; fprintf(stderr,"tuning DVB-T to %lu Hz\n", freq); fprintf(stderr,"inv:%d bw:%d fecH:%d fecL:%d mod:%d tm:%d gi:%d hier:%d\n", chan->tp.inversion, chan->tp.bandwidth, chan->tp.coderateH, chan->tp.coderateL, chan->tp.modulation, @@ -352,11 +406,16 @@ bool DvbStream::tuneDvb( ChannelDesc *chan, bool dvr ) break; } case FE_QAM : { + cmdargs[0].cmd = DTV_DELIVERY_SYSTEM; cmdargs[0].u.data = SYS_DVBC_ANNEX_AC; + cmdargs[1].cmd = DTV_FREQUENCY; cmdargs[1].u.data = freq; + cmdargs[2].cmd = DTV_MODULATION; cmdargs[2].u.data = chan->tp.modulation; + cmdargs[3].cmd = DTV_SYMBOL_RATE; cmdargs[3].u.data = srate; + cmdargs[4].cmd = DTV_INNER_FEC; cmdargs[4].u.data = chan->tp.coderateH; + cmdargs[5].cmd = DTV_INVERSION; cmdargs[5].u.data = inversion; + cmdargs[6].cmd = DTV_TUNE; + cmdseq.num = 7; + cmdseq.props = cmdargs; fprintf(stderr,"tuning DVB-C to %lu\n", freq); - feparams.frequency=freq; - feparams.u.qam.symbol_rate = srate; - feparams.u.qam.fec_inner = chan->tp.coderateH; - feparams.u.qam.modulation = chan->tp.modulation; fprintf(stderr,"inv:%d sr:%lu fecH:%d mod:%d\n", chan->tp.inversion, srate, chan->tp.coderateH, chan->tp.modulation ); break; @@ -384,51 +443,78 @@ bool DvbStream::tuneDvb( ChannelDesc *chan, bool dvr ) lof = (dvbDevice->lnb[lnbPos].loFreq*1000); } if ( freq<lof ) - feparams.frequency = ( lof-freq ); + freq = ( lof-freq ); else - feparams.frequency = ( freq-lof ); + freq = ( freq-lof ); } - else - feparams.frequency=freq; - - feparams.u.qpsk.symbol_rate=srate; - feparams.u.qpsk.fec_inner=chan->tp.coderateH; - fprintf(stderr,"inv:%d fecH:%d\n", chan->tp.inversion, chan->tp.coderateH ); + fprintf(stderr,"inv:%d fecH:%d mod:%d\n", chan->tp.inversion, chan->tp.coderateH, chan->tp.modulation ); if ( setDiseqc( lnbPos, chan, hiband, rotorMove, dvr )!=0 ) { closeFe(); return false; } + fprintf( stderr, "Diseqc settings time = %d ms\n", t1.msecsTo( QTime::currentTime() ) ); + t1 = QTime::currentTime(); + if ( chan->tp.S2 ) { + fprintf(stderr,"\nTHIS IS DVB-S2 >>>>>>>>>>>>>>>>>>>\n"); + cmdargs[0].cmd = DTV_DELIVERY_SYSTEM; cmdargs[0].u.data = SYS_DVBS2; + cmdargs[1].cmd = DTV_FREQUENCY; cmdargs[1].u.data = freq; + cmdargs[2].cmd = DTV_MODULATION; cmdargs[2].u.data = chan->tp.modulation; + cmdargs[3].cmd = DTV_SYMBOL_RATE; cmdargs[3].u.data = srate; + cmdargs[4].cmd = DTV_INNER_FEC; cmdargs[4].u.data = chan->tp.coderateH; + cmdargs[5].cmd = DTV_PILOT; cmdargs[5].u.data = PILOT_AUTO; + cmdargs[6].cmd = DTV_ROLLOFF; cmdargs[6].u.data = chan->tp.rolloff; + cmdargs[7].cmd = DTV_INVERSION; cmdargs[7].u.data = inversion; + cmdargs[8].cmd = DTV_TUNE; + cmdseq.num = 9; + cmdseq.props = cmdargs; + } + else { + cmdargs[0].cmd = DTV_DELIVERY_SYSTEM; cmdargs[0].u.data = SYS_DVBS; + cmdargs[1].cmd = DTV_FREQUENCY; cmdargs[1].u.data = freq; + cmdargs[2].cmd = DTV_MODULATION; cmdargs[2].u.data = chan->tp.modulation; + if ( chan->tp.modulation==QAM_AUTO ) + cmdargs[2].u.data = QPSK; + cmdargs[3].cmd = DTV_SYMBOL_RATE; cmdargs[3].u.data = srate; + cmdargs[4].cmd = DTV_INNER_FEC; cmdargs[4].u.data = chan->tp.coderateH; + cmdargs[5].cmd = DTV_INVERSION; cmdargs[5].u.data = inversion; + cmdargs[6].cmd = DTV_TUNE; + cmdseq.num = 7; + cmdseq.props = cmdargs; + } break; } case FE_ATSC : { + cmdargs[0].cmd = DTV_DELIVERY_SYSTEM; cmdargs[0].u.data = SYS_ATSC; + cmdargs[1].cmd = DTV_FREQUENCY; cmdargs[1].u.data = freq; + cmdargs[2].cmd = DTV_MODULATION; cmdargs[2].u.data = chan->tp.modulation; + cmdargs[3].cmd = DTV_INVERSION; cmdargs[3].u.data = inversion; + cmdargs[4].cmd = DTV_TUNE; + cmdseq.num = 5; + cmdseq.props = cmdargs; fprintf(stderr,"tuning ATSC to %lu\n", freq); - feparams.frequency=freq; - feparams.u.vsb.modulation = chan->tp.modulation; fprintf(stderr,"inv:%d mod:%d\n", chan->tp.inversion, chan->tp.modulation ); break; } } - if ( chan->tp.inversion==INVERSION_AUTO ) { - if ( fe_info.caps & FE_CAN_INVERSION_AUTO ) - feparams.inversion=chan->tp.inversion; - else { - fprintf(stderr,"Can NOT inversion_auto\n"); - feparams.inversion=INVERSION_OFF; - } - } - else - feparams.inversion=chan->tp.inversion; - if ( rotorMove ) + if ( rotorMove ) { + if ( ioctl( fdFrontend, FE_SET_PROPERTY, &cmdseq )<0 ) { + perror("ERROR tuning\n"); + closeFe(); + return false; + } + moveRotor( lnbPos, chan, hiband, dvr ); loop = 2; + } while ( loop>-1 ) { - if (ioctl(fdFrontend,FE_SET_FRONTEND,&feparams) < 0) { - perror("ERROR tuning \n"); + if ( ioctl( fdFrontend, FE_SET_PROPERTY, &cmdseq )<0 ) { + perror("ERROR tuning\n"); closeFe(); return false; } - for ( i=0; i<(dvbDevice->tuningTimeout/100); i++ ) { + QTime lockTime = QTime::currentTime(); + do { usleep( 100000 ); fprintf( stderr, "." ); if ( ioctl( fdFrontend, FE_READ_STATUS, &status )==-1 ) { @@ -440,7 +526,7 @@ bool DvbStream::tuneDvb( ChannelDesc *chan, bool dvr ) loop = 0; break; } - } + } while ( lockTime.msecsTo( QTime::currentTime() )<=dvbDevice->tuningTimeout ); fprintf(stderr,"\n"); --loop; } @@ -451,6 +537,8 @@ bool DvbStream::tuneDvb( ChannelDesc *chan, bool dvr ) return false; } + fprintf( stderr, "Tuning time = %d ms\n", t1.msecsTo( QTime::currentTime() ) ); + if ( rotorMove ) dvbDevice->lnb[lnbPos].currentSource = chan->tp.source; @@ -496,6 +584,23 @@ int DvbStream::setDiseqc( int switchPos, ChannelDesc *chan, int hiband, int &rot int i; int voltage18 = ( (chan->tp.pol=='H')||(chan->tp.pol=='h') ); int ci = 4 * switchPos + 2 * hiband + (voltage18 ? 1 : 0); + bool secMini = false; + bool hasRotor = false; + bool hasSwitch = true; + + if ( dvbDevice->numLnb<2 ) + hasSwitch = false; + + if ( dvbDevice->lnb[switchPos].rotorType!=0 && dvbDevice->lnb[switchPos].rotorType!=3 ) + hasRotor = true; + + if ( dvbDevice->numLnb==2 && dvbDevice->secMini ) + secMini = true; + + if ( dvbDevice->secTwice ) + diseqcTwice = 2; + else + diseqcTwice = 1; fprintf( stderr, "DiSEqC: switch pos %i, %sV, %sband (index %d)\n", switchPos, voltage18 ? "18" : "13", hiband ? "hi" : "lo", ci ); if ( ci < 0 || ci >= (int)(sizeof(switchCmd)/sizeof(struct dvb_diseqc_master_cmd)) ) @@ -507,85 +612,108 @@ int DvbStream::setDiseqc( int switchPos, ChannelDesc *chan, int hiband, int &rot if ( ioctl(fdFrontend, FE_SET_VOLTAGE, ci%2 ? SEC_VOLTAGE_18 : SEC_VOLTAGE_13) ) perror("FE_SET_VOLTAGE failed"); - fprintf( stderr, "DiSEqC: %02x %02x %02x %02x %02x %02x\n", switchCmd[ci].msg[0], switchCmd[ci].msg[1], switchCmd[ci].msg[2], switchCmd[ci].msg[3], switchCmd[ci].msg[4], switchCmd[ci].msg[5] ); - for ( i=0; i<2; ++i ) { - usleep(15*1000); - if ( ioctl(fdFrontend, FE_DISEQC_SEND_MASTER_CMD, &switchCmd[ci]) ) - perror("FE_DISEQC_SEND_MASTER_CMD failed"); - } - - QString msg; - if ( dvbDevice->lnb[switchPos].rotorType!=0 && chan->tp.source!=dvbDevice->lnb[switchPos].currentSource ) { - int i, index=-1; - double angle=0.0, oldAngle=0.0; - fprintf( stderr, "Driving rotor to %s\n", chan->tp.source.ascii() ); - for ( i=0; i<(int)dvbDevice->lnb[switchPos].source.count(); i++ ) { - if ( dvbDevice->lnb[switchPos].source[i]==chan->tp.source ) { - index = i; - break; + if ( hasSwitch ) { + if ( !secMini ) { + fprintf( stderr, "DiSEqC: %02x %02x %02x %02x %02x %02x\n", switchCmd[ci].msg[0], switchCmd[ci].msg[1], switchCmd[ci].msg[2], switchCmd[ci].msg[3], switchCmd[ci].msg[4], switchCmd[ci].msg[5] ); + for ( i=0; i<diseqcTwice; ++i ) { + usleep(15*1000); + if ( ioctl(fdFrontend, FE_DISEQC_SEND_MASTER_CMD, &switchCmd[ci]) ) + perror("FE_DISEQC_SEND_MASTER_CMD failed"); } } - angle = getSourceAngle( chan->tp.source ); - if ( dvbDevice->lnb[switchPos].rotorType==1 ) { - fprintf( stderr, "Rotor: gotoX=%f\n", angle ); - gotoX( angle ); - } - else { - int pos = dvbDevice->lnb[switchPos].position[index]; - fprintf( stderr, "Rotor: gotoN=%d\n", pos ); - rotorCommand( 9, pos ); - } - if ( dvbDevice->lnb[switchPos].currentSource.isEmpty() ) { - rotor = 10; - msg = i18n("Moving rotor from unknown position..."); - } else { - oldAngle = getSourceAngle( dvbDevice->lnb[switchPos].currentSource ); - fprintf( stderr, "old rotor pos: %f °\n", oldAngle ); - fprintf( stderr, "new rotor pos: %f °\n", angle ); - angle = fabs(angle-oldAngle); - fprintf( stderr, "Rotation angle: %f °\n", angle ); - if ( voltage18 ) - rotor = (int)(angle*dvbDevice->lnb[switchPos].speed18v)+1; - else - rotor = (int)(angle*dvbDevice->lnb[switchPos].speed13v)+1; - msg = i18n("Moving rotor..."); + fprintf( stderr, "DiSEqC: mini_diseqc\n" ); + for ( i=0; i<diseqcTwice; ++i ) { + usleep(15*1000); + if ( ioctl(fdFrontend, FE_DISEQC_SEND_BURST, (ci/4)%2 ? SEC_MINI_B : SEC_MINI_A) ) + perror("FE_DISEQC_SEND_BURST failed"); + } } - fprintf( stderr, "Rotation time: %d sec.\n", rotor ); } - if ( rotor ) { - int j; - if ( !dvr ) { - for ( j=0; j<(rotor*2); j++ ) { - usleep( 500000 ); - } + if ( hasRotor && chan->tp.source!=dvbDevice->lnb[switchPos].currentSource ) { + rotor = 1; + return 0; + } + + if ( (ci/2)%2 ) { + usleep(15*1000); + if ( ioctl(fdFrontend, FE_SET_TONE, SEC_TONE_ON) ) + perror("FE_SET_TONE failed"); + } + + return 0; +} + + + +void DvbStream::moveRotor( int switchPos, ChannelDesc *chan, int hiband, bool dvr ) +{ + int i, j, index=-1; + double angle=0.0, oldAngle=0.0; + int rotor=0; + int voltage18 = ( (chan->tp.pol=='H')||(chan->tp.pol=='h') ); + int ci = 4 * switchPos + 2 * hiband + (voltage18 ? 1 : 0); + QString msg; + + fprintf( stderr, "Driving rotor to %s\n", chan->tp.source.ascii() ); + for ( i=0; i<(int)dvbDevice->lnb[switchPos].source.count(); i++ ) { + if ( dvbDevice->lnb[switchPos].source[i]==chan->tp.source ) { + index = i; + break; } - else { - QProgressDialog progress( msg, i18n("Cancel"), rotor*2, 0, "progress", true ); - for ( j=0; j<(rotor*2); j++ ) { - progress.setProgress( j ); - qApp->processEvents(); - if ( progress.wasCanceled() ) - break; - usleep( 500000 ); - } - progress.setProgress( rotor*2 ); + } + angle = getSourceAngle( chan->tp.source ); + if ( dvbDevice->lnb[switchPos].rotorType==1 ) { + fprintf( stderr, "Rotor: gotoX=%f\n", angle ); + gotoX( angle ); + } + else { + int pos = dvbDevice->lnb[switchPos].position[index]; + fprintf( stderr, "Rotor: gotoN=%d\n", pos ); + rotorCommand( 9, pos ); + } + if ( dvbDevice->lnb[switchPos].currentSource.isEmpty() ) { + rotor = 10; + msg = i18n("Moving rotor from unknown position..."); + } + else { + oldAngle = getSourceAngle( dvbDevice->lnb[switchPos].currentSource ); + fprintf( stderr, "old rotor pos: %f °\n", oldAngle ); + fprintf( stderr, "new rotor pos: %f °\n", angle ); + angle = fabs(angle-oldAngle); + fprintf( stderr, "Rotation angle: %f °\n", angle ); + if ( voltage18 ) + rotor = (int)(angle*dvbDevice->lnb[switchPos].speed18v)+1; + else + rotor = (int)(angle*dvbDevice->lnb[switchPos].speed13v)+1; + msg = i18n("Moving rotor..."); + } + fprintf( stderr, "Rotation time: %d sec.\n", rotor ); + + if ( !dvr ) { + for ( j=0; j<(rotor*2); j++ ) { + usleep( 500000 ); + } + } + else { + QProgressDialog progress( msg, i18n("Cancel"), rotor*2, 0, "progress", true ); + for ( j=0; j<(rotor*2); j++ ) { + progress.setProgress( j ); qApp->processEvents(); + if ( progress.wasCanceled() ) + break; + usleep( 500000 ); } + progress.setProgress( rotor*2 ); + qApp->processEvents(); } - for ( i=0; i<2; ++i ) { + if ( (ci/2)%2 ) { usleep(15*1000); - if ( ioctl(fdFrontend, FE_DISEQC_SEND_BURST, (ci/4)%2 ? SEC_MINI_B : SEC_MINI_A) ) - perror("FE_DISEQC_SEND_BURST failed"); + if ( ioctl(fdFrontend, FE_SET_TONE, SEC_TONE_ON) ) + perror("FE_SET_TONE failed"); } - - usleep(15*1000); - if ( ioctl(fdFrontend, FE_SET_TONE, (ci/2)%2 ? SEC_TONE_ON : SEC_TONE_OFF) ) - perror("FE_SET_TONE failed"); - - return 0; } @@ -681,7 +809,7 @@ void DvbStream::rotorCommand( int cmd, int n1, int n2, int n3 ) }; int i; - for ( i=0; i<2; ++i ) { + for ( i=0; i<diseqcTwice; ++i ) { usleep(15*1000); if ( ioctl( fdFrontend, FE_DISEQC_SEND_MASTER_CMD, &cmds[cmd] ) ) perror("Rotor : FE_DISEQC_SEND_MASTER_CMD failed"); @@ -803,28 +931,33 @@ bool DvbStream::hasVideo() void DvbStream::run() { - unsigned char buf[188]; + int READSIZE = 188*20; + int BUFSIZE = 188*100; + int WSIZE = 188*64; + unsigned char buf[READSIZE]; + unsigned char thBuf[BUFSIZE]; int n, i, thWrite=0; - int WSIZE=188*8; DVBout *o=0; signal( SIGPIPE, SIG_IGN ); while ( isRunning ) { if ( poll( &pfd, 1, 100 ) ) { - n = read( fdDvr, buf, 188 ); - if ( n==188 ) { + n = read( fdDvr, buf, READSIZE ); + if ( n && !(n%188) ) { + //fprintf( stderr, "DVR0: read : %d\n", n ); memcpy( thBuf+thWrite, buf, n ); thWrite+=n; - if ( thWrite==WSIZE ) { + if ( thWrite>=WSIZE ) { for ( i=0; i<(int)out.count(); i++ ) - out.at(i)->process( thBuf, WSIZE ); + out.at(i)->process( thBuf, thWrite ); thWrite = 0; } } + else + fprintf( stderr, "DVR0: read failed : %d\n", n ); + } - else - usleep(1000); if ( waitPause>0 ) { o = 0; @@ -917,19 +1050,11 @@ void DvbStream::recordEnded( DVBout *o, RecTimer* t, bool kill ) if ( kill ) { removePids( o ); + if ( cam ) + cam->stopService( &(o->channel) ); removeOut( o ); if ( out.count()==0 ) stop(); - else if ( cam ) { - for ( i=0; i<(int)out.count(); i++ ) { - if ( out.at(i)->channel.fta ) { - i=-1; - break; - } - } - if ( i!=-1 ) - cam->stop(); - } } recordingState(); if ( t ) @@ -986,6 +1111,8 @@ void DvbStream::stopBroadcast() } for ( i=0; i<(int)p.count(); i++ ) { removePids( p.at(i) ); + if ( cam ) + cam->stopService( &(p.at(i)->channel) ); removeOut( p.at(i) ); } if ( out.count()==0 ) @@ -1002,7 +1129,7 @@ int DvbStream::canStartBroadcast( bool &live, ChannelDesc *chan ) for ( i=0; i<(int)out.count(); i++ ) { if ( (chan->tp!=out.at(i)->channel.tp) && out.at(i)->hasRec() ) return ErrIsRecording; - if ( cam && out.at(i)->hasRec() && out.at(i)->channel.fta && chan->fta && out.at(i)->channel.sid!=chan->sid ) + if ( chan->fta && cam && !cam->canPlay( chan ) ) return ErrCamUsed; if ( out.at(i)->hasLive() && chan->tp!=out.at(i)->channel.tp ) live = true; @@ -1070,6 +1197,8 @@ bool DvbStream::startBroadcast( QPtrList<ChannelDesc> *list, Ts2Rtp *rtp ) else { broadcastList.append( new ChannelDesc( *list->at(i) ) ); no++; + if ( list->at(i)->fta && cam ) + cam->startService( list->at(i) ); } } } @@ -1102,15 +1231,11 @@ int DvbStream::canStartTimer( bool &live, ChannelDesc *chan ) return ErrIsRecording; if ( (o->channel.name==chan->name) && o->hasRec() ) return ErrIsRecording; - if ( (chan->tp==o->channel.tp) && o->hasRec() ) { - if ( chan->fta && cam && o->channel.fta ) - return ErrCamUsed; - } + if ( chan->fta && cam && !cam->canPlay( chan ) ) + return ErrCamUsed; if ( o->hasLive() ) { if ( chan->tp!=o->channel.tp ) live = true; - else if ( cam && chan->fta && o->channel.fta ) - live = true; } } return ret; @@ -1194,8 +1319,8 @@ bool DvbStream::startTimer( ChannelDesc *chan, QString path, int maxsize, RecTim } fprintf(stderr,"NOUT: %d\n", out.count() ); - if ( chan->fta && cam && ( ((cam->running() && chan->sid!=cam->serviceId()) || !cam->running()) ) ) - cam->restart( chan->sid ); + if ( chan->fta && cam ) + cam->startService( chan ); startReading(); @@ -1205,7 +1330,7 @@ bool DvbStream::startTimer( ChannelDesc *chan, QString path, int maxsize, RecTim -int DvbStream::goLive( ChannelDesc *chan, const QString &pipeName ) +int DvbStream::goLive( ChannelDesc *chan, const QString &pipeName, int ringBufSize ) { int i; bool stop=false; @@ -1216,10 +1341,8 @@ int DvbStream::goLive( ChannelDesc *chan, const QString &pipeName ) return ErrIsRecording; if ( (chan->tp!=out.at(i)->channel.tp) && out.at(i)->hasBroadcast() ) return ErrIsBroadcasting; - if ( (chan->tp==out.at(i)->channel.tp) && (out.at(i)->hasBroadcast() || out.at(i)->hasRec())) { - if ( chan->fta && cam && cam->running() && (cam->serviceId()!=chan->sid) ) - return ErrCamUsed; - } + if ( chan->fta && cam && !cam->canPlay( chan ) ) + return ErrCamUsed; if ( out.at(i)->channel.name==chan->name ) o = out.at(i); } @@ -1259,11 +1382,11 @@ int DvbStream::goLive( ChannelDesc *chan, const QString &pipeName ) else i = 0; - o->goLive( pipeName ); + o->goLive( pipeName, ringBufSize ); fprintf(stderr,"NOUT: %d\n", out.count() ); - if ( chan->fta && cam && !cam->running() ) - cam->restart( chan->sid ); + if ( chan->fta && cam ) + cam->startService( chan ); startReading(); return i; @@ -1307,17 +1430,12 @@ void DvbStream::stopLive( ChannelDesc *chan ) } for ( i=0; i<(int)p.count(); i++ ) { removePids( p.at(i) ); + if ( cam ) + cam->stopService( &(p.at(i)->channel) ); removeOut( p.at(i) ); } fprintf(stderr,"Live stopped\n"); - if ( cam ) { - for ( i=0; i<(int)out.count(); i++ ) { - if ( out.at(i)->channel.fta ) - camUsed = true; - } - } - if ( cam && !camUsed ) - cam->stop(); + if ( out.count()==0 && chan->tp!=currentTransponder ) stop(); } @@ -1343,8 +1461,6 @@ void DvbStream::stop() wait(); fprintf(stderr,"dvbstream::run() terminated\n"); } - if ( cam ) - cam->stop(); dvbEvents->stop(); stopFrontend(); } @@ -1381,7 +1497,6 @@ DvbStream::~DvbStream() { stop(); if ( cam ) { - cam->stop(); delete cam; } delete dvbEvents; diff --git a/kaffeine/src/input/dvb/dvbstream.h b/kaffeine/src/input/dvb/dvbstream.h index a5deb52..fe85f04 100644 --- a/kaffeine/src/input/dvb/dvbstream.h +++ b/kaffeine/src/input/dvb/dvbstream.h @@ -62,10 +62,11 @@ public : void setPlug( KaffeineDvbPlugin *p ); QStringList getSources( bool all=false ); bool canSource( ChannelDesc *chan ); + int getPriority(); bool tuneDvb( ChannelDesc *chan, bool dvr=true ); void stopFrontend(); virtual void run(); - int goLive( ChannelDesc *chan, const QString &pipeName ); + int goLive( ChannelDesc *chan, const QString &pipeName, int ringBufSize ); void preStopLive(); void stopLive( ChannelDesc *chan ); void stop(); @@ -89,8 +90,9 @@ public : bool hasLive(); bool liveIsRecording(); int getSNR(); + void probeCam(); + void showCamDialog(); - unsigned char thBuf[188*10]; struct pollfd pfd; DVBevents *dvbEvents; @@ -109,6 +111,7 @@ protected: private : int setDiseqc( int switchPos, ChannelDesc *chan, int hiband, int &rotor, bool dvr ); + void moveRotor( int switchPos, ChannelDesc *chan, int hiband, bool dvr ); void rotorCommand( int cmd, int n1=0, int n2=0, int n3=0 ); void gotoX( double azimuth ); double getAzimuth( double angle ); @@ -119,7 +122,6 @@ private : void removeOut( DVBout *o ); void recordingState(); void startReading(); - void probeCam(); bool openFe(); bool closeFe(); void connectStatus( bool con ); @@ -143,6 +145,7 @@ private : QString timeShiftFileName; DvbCam *cam; bool camProbed; + int diseqcTwice; KaffeineDvbPlugin *plug; signals: diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/Makefile.am b/kaffeine/src/input/dvb/lib/libdvbapi/Makefile.am index 59f288b..9963cd4 100644 --- a/kaffeine/src/input/dvb/lib/libdvbapi/Makefile.am +++ b/kaffeine/src/input/dvb/lib/libdvbapi/Makefile.am @@ -2,10 +2,11 @@ noinst_LTLIBRARIES = libdvbapi.la INCLUDES = -I$(top_srcdir)/kaffeine/src/input/dvb/lib -libdvbapi_la_SOURCES = diseqc.c \ +libdvbapi_la_SOURCES = dvbaudio.c \ dvbca.c \ dvbdemux.c \ dvbfe.c \ - dvbnet.c + dvbnet.c \ + dvbvideo.c CFLAGS = -g -O2 -Wall -Wshadow -Wpointer-arith -Wstrict-prototypes -fPIC diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/dvbaudio.c b/kaffeine/src/input/dvb/lib/libdvbapi/dvbaudio.c new file mode 100644 index 0000000..72b4d70 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvbapi/dvbaudio.c @@ -0,0 +1,50 @@ +/* + * libdvbnet - a DVB network support library + * + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <sys/param.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <linux/dvb/audio.h> +#include <errno.h> +#include "dvbaudio.h" + +int dvbaudio_open(int adapter, int audiodeviceid) +{ + char filename[PATH_MAX+1]; + int fd; + + sprintf(filename, "/dev/dvb/adapter%i/audio%i", adapter, audiodeviceid); + if ((fd = open(filename, O_RDWR)) < 0) { + // if that failed, try a flat /dev structure + sprintf(filename, "/dev/dvb%i.audio%i", adapter, audiodeviceid); + fd = open(filename, O_RDWR); + } + + return fd; +} + +int dvbaudio_set_bypass(int fd, int bypass) +{ + return ioctl(fd, AUDIO_SET_BYPASS_MODE, bypass); +} diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/dvbaudio.h b/kaffeine/src/input/dvb/lib/libdvbapi/dvbaudio.h new file mode 100644 index 0000000..36f6a55 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvbapi/dvbaudio.h @@ -0,0 +1,55 @@ +/* + * libdvbnet - a DVB network support library + * + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef LIBDVBAUDIO_H +#define LIBDVBAUDIO_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdint.h> + +/** + * Open a DVB audio device. + * + * @param adapter DVB adapter ID. + * @param audiodeviceid Id of audio device of that adapter to open. + * @return A unix file descriptor on success, or -1 on failure. + */ +extern int dvbaudio_open(int adapter, int audiodeviceid); + +/** + * Control audio bypass - i.e. output decoded audio, or the raw bitstream (e.g. AC3). + * + * @param fd Audio device opened with dvbaudio_open(). + * @param bypass 1=> enable bypass, 0=> disable. + * @return 0 on success, nonzero on failure. + */ +extern int dvbaudio_set_bypass(int fd, int bypass); + +// FIXME: this is a stub library + +#ifdef __cplusplus +} +#endif + +#endif // LIBDVBAUDIO_H diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/dvbdemux.c b/kaffeine/src/input/dvb/lib/libdvbapi/dvbdemux.c index aebad34..a882af6 100644 --- a/kaffeine/src/input/dvb/lib/libdvbapi/dvbdemux.c +++ b/kaffeine/src/input/dvb/lib/libdvbapi/dvbdemux.c @@ -128,6 +128,12 @@ int dvbdemux_set_pes_filter(int fd, int pid, filter.output = DMX_OUT_TS_TAP; break; +#ifdef DMX_OUT_TSDEMUX_TAP + case DVBDEMUX_OUTPUT_TS_DEMUX: + filter.output = DMX_OUT_TSDEMUX_TAP; + break; +#endif + default: return -EINVAL; } @@ -201,6 +207,12 @@ int dvbdemux_set_pid_filter(int fd, int pid, filter.output = DMX_OUT_TS_TAP; break; +#ifdef DMX_OUT_TSDEMUX_TAP + case DVBDEMUX_OUTPUT_TS_DEMUX: + filter.output = DMX_OUT_TSDEMUX_TAP; + break; +#endif + default: return -EINVAL; } diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/dvbdemux.h b/kaffeine/src/input/dvb/lib/libdvbapi/dvbdemux.h index 3fe4a4b..808ee80 100644 --- a/kaffeine/src/input/dvb/lib/libdvbapi/dvbdemux.h +++ b/kaffeine/src/input/dvb/lib/libdvbapi/dvbdemux.h @@ -55,6 +55,7 @@ extern "C" #define DVBDEMUX_OUTPUT_DECODER 0 #define DVBDEMUX_OUTPUT_DEMUX 1 #define DVBDEMUX_OUTPUT_DVR 2 +#define DVBDEMUX_OUTPUT_TS_DEMUX 3 /** * PES types. @@ -65,6 +66,7 @@ extern "C" #define DVBDEMUX_PESTYPE_SUBTITLE 3 #define DVBDEMUX_PESTYPE_PCR 4 + /** * Open a demux device. Can be called multiple times. These let you setup a * single filter per FD. It can can also be read() from if you use a section @@ -78,8 +80,8 @@ extern "C" extern int dvbdemux_open_demux(int adapter, int demuxdevice, int nonblocking); /** - * Open a DVR device. May be opened for writing once, or multiple times in readonly - * mode. It is used to either write() transport stream data to be demuxed + * Open a DVR device. May be opened for writing or reading once. + * It is used to either write() transport stream data to be demuxed * (if input == DVBDEMUX_INPUT_DVR), or to read() a stream of demuxed data * (if output == DVBDEMUX_OUTPUT_DVR). * diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/dvbfe.c b/kaffeine/src/input/dvb/lib/libdvbapi/dvbfe.c index fc6ecf4..98104c9 100644 --- a/kaffeine/src/input/dvb/lib/libdvbapi/dvbfe.c +++ b/kaffeine/src/input/dvb/lib/libdvbapi/dvbfe.c @@ -2,6 +2,7 @@ * libdvbfe - a DVB frontend library * * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * Copyright (C) 2005 Manu Abraham <abraham.manu@gmail.com> * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) * * This library is free software; you can redistribute it and/or @@ -26,14 +27,16 @@ #include <sys/param.h> #include <sys/ioctl.h> #include <sys/time.h> +#include <sys/poll.h> #include <fcntl.h> #include <unistd.h> #include <ctype.h> #include <errno.h> #include <linux/dvb/frontend.h> +#include <libdvbmisc/dvbmisc.h> #include "dvbfe.h" -#define GET_INFO_MIN_DELAY_US 100000 +int verbose = 0; static int dvbfe_spectral_inversion_to_kapi[][2] = { @@ -128,6 +131,7 @@ static int dvbfe_dvbt_hierarchy_to_kapi[][2] = { -1, -1 } }; + static int lookupval(int val, int reverse, int table[][2]) { int i =0; @@ -149,19 +153,16 @@ static int lookupval(int val, int reverse, int table[][2]) } -struct dvbfe_handle_prv { +struct dvbfe_handle { int fd; - dvbfe_type_t type; + enum dvbfe_type type; char *name; - struct timeval nextinfotime; - struct dvbfe_info cachedinfo; - int cachedreturnval; }; -dvbfe_handle_t dvbfe_open(int adapter, int frontend, int readonly) +struct dvbfe_handle *dvbfe_open(int adapter, int frontend, int readonly) { char filename[PATH_MAX+1]; - struct dvbfe_handle_prv *fehandle; + struct dvbfe_handle *fehandle; int fd; struct dvb_frontend_info info; @@ -188,8 +189,8 @@ dvbfe_handle_t dvbfe_open(int adapter, int frontend, int readonly) } // setup structure - fehandle = (struct dvbfe_handle_prv*) malloc(sizeof(struct dvbfe_handle_prv)); - memset(fehandle, 0, sizeof(struct dvbfe_handle_prv)); + fehandle = (struct dvbfe_handle*) malloc(sizeof(struct dvbfe_handle)); + memset(fehandle, 0, sizeof(struct dvbfe_handle)); fehandle->fd = fd; switch(info.type) { case FE_QPSK: @@ -214,99 +215,118 @@ dvbfe_handle_t dvbfe_open(int adapter, int frontend, int readonly) return fehandle; } -void dvbfe_close(dvbfe_handle_t _fehandle) +void dvbfe_close(struct dvbfe_handle *fehandle) { - struct dvbfe_handle_prv *fehandle = (struct dvbfe_handle_prv*) _fehandle; - close(fehandle->fd); free(fehandle->name); free(fehandle); } -int dvbfe_get_info(dvbfe_handle_t _fehandle, dvbfe_info_mask_t querymask, struct dvbfe_info *result) +extern int dvbfe_get_info(struct dvbfe_handle *fehandle, + enum dvbfe_info_mask querymask, + struct dvbfe_info *result, + enum dvbfe_info_querytype querytype, + int timeout) { int returnval = 0; - fe_status_t status; - struct dvb_frontend_parameters kparams; - struct dvbfe_handle_prv *fehandle = (struct dvbfe_handle_prv*) _fehandle; - struct timeval curtime; - - // limit how often this is called to reduce bus traffic - gettimeofday(&curtime, NULL); - if ((curtime.tv_sec < fehandle->nextinfotime.tv_sec) || - ((curtime.tv_sec == fehandle->nextinfotime.tv_sec) && (curtime.tv_usec < fehandle->nextinfotime.tv_usec))) { - memcpy(result, &fehandle->cachedinfo, sizeof(struct dvbfe_info)); - return fehandle->cachedreturnval; - } + struct dvb_frontend_event kevent; + int ok = 0; - // retrieve the requested values - memset(result, 0, sizeof(result)); - result->type = fehandle->type; result->name = fehandle->name; - if (querymask & DVBFE_INFO_LOCKSTATUS) { - if (!ioctl(fehandle->fd, FE_READ_STATUS, &status)) { - returnval |= DVBFE_INFO_LOCKSTATUS; - if (status & FE_HAS_SIGNAL) - result->signal = 1; - - if (status & FE_HAS_CARRIER) - result->carrier = 1; + result->type = fehandle->type; - if (status & FE_HAS_VITERBI) - result->viterbi = 1; + switch(querytype) { + case DVBFE_INFO_QUERYTYPE_IMMEDIATE: + if (querymask & DVBFE_INFO_LOCKSTATUS) { + if (!ioctl(fehandle->fd, FE_READ_STATUS, &kevent.status)) { + returnval |= DVBFE_INFO_LOCKSTATUS; + } + } + if (querymask & DVBFE_INFO_FEPARAMS) { + if (!ioctl(fehandle->fd, FE_GET_FRONTEND, &kevent.parameters)) { + returnval |= DVBFE_INFO_FEPARAMS; + } + } + break; - if (status & FE_HAS_SYNC) - result->sync = 1; + case DVBFE_INFO_QUERYTYPE_LOCKCHANGE: + { + struct pollfd pollfd; + pollfd.fd = fehandle->fd; + pollfd.events = POLLIN | POLLERR; + + ok = 1; + if (poll(&pollfd, 1, timeout) < 0) + ok = 0; + if (pollfd.revents & POLLERR) + ok = 0; + if (!(pollfd.revents & POLLIN)) + ok = 0; + } - if (status & FE_HAS_LOCK) - result->lock = 1; + if (ok && + ((querymask & DVBFE_INFO_LOCKSTATUS) || + (querymask & DVBFE_INFO_FEPARAMS))) { + if (!ioctl(fehandle->fd, FE_GET_EVENT, &kevent)) { + if (querymask & DVBFE_INFO_LOCKSTATUS) + returnval |= DVBFE_INFO_LOCKSTATUS; + if (querymask & DVBFE_INFO_FEPARAMS) + returnval |= DVBFE_INFO_FEPARAMS; + } } + break; } - if (querymask & DVBFE_INFO_FEPARAMS) { - if (!ioctl(fehandle->fd, FE_GET_FRONTEND, &kparams)) { - returnval |= DVBFE_INFO_FEPARAMS; - result->feparams.frequency = kparams.frequency; - result->feparams.inversion = lookupval(kparams.inversion, 1, dvbfe_spectral_inversion_to_kapi); - switch(fehandle->type) { - case FE_QPSK: - result->feparams.u.dvbs.symbol_rate = kparams.u.qpsk.symbol_rate; - result->feparams.u.dvbs.fec_inner = - lookupval(kparams.u.qpsk.fec_inner, 1, dvbfe_code_rate_to_kapi); - break; - case FE_QAM: - result->feparams.u.dvbc.symbol_rate = kparams.u.qam.symbol_rate; - result->feparams.u.dvbc.fec_inner = - lookupval(kparams.u.qam.fec_inner, 1, dvbfe_code_rate_to_kapi); - result->feparams.u.dvbc.modulation = - lookupval(kparams.u.qam.modulation, 1, dvbfe_dvbc_mod_to_kapi); - break; + if (returnval & DVBFE_INFO_LOCKSTATUS) { + result->signal = kevent.status & FE_HAS_SIGNAL ? 1 : 0; + result->carrier = kevent.status & FE_HAS_CARRIER ? 1 : 0; + result->viterbi = kevent.status & FE_HAS_VITERBI ? 1 : 0; + result->sync = kevent.status & FE_HAS_SYNC ? 1 : 0; + result->lock = kevent.status & FE_HAS_LOCK ? 1 : 0; + } - case FE_OFDM: - result->feparams.u.dvbt.bandwidth = - lookupval(kparams.u.ofdm.bandwidth, 1, dvbfe_dvbt_bandwidth_to_kapi); - result->feparams.u.dvbt.code_rate_HP = - lookupval(kparams.u.ofdm.code_rate_HP, 1, dvbfe_code_rate_to_kapi); - result->feparams.u.dvbt.code_rate_LP = - lookupval(kparams.u.ofdm.code_rate_LP, 1, dvbfe_code_rate_to_kapi); - result->feparams.u.dvbt.constellation = - lookupval(kparams.u.ofdm.constellation, 1, dvbfe_dvbt_const_to_kapi); - result->feparams.u.dvbt.transmission_mode = - lookupval(kparams.u.ofdm.transmission_mode, 1, dvbfe_dvbt_transmit_mode_to_kapi); - result->feparams.u.dvbt.guard_interval = - lookupval(kparams.u.ofdm.guard_interval, 1, dvbfe_dvbt_guard_interval_to_kapi); - result->feparams.u.dvbt.hierarchy_information = - lookupval(kparams.u.ofdm.hierarchy_information, 1, dvbfe_dvbt_hierarchy_to_kapi); - break; + if (returnval & DVBFE_INFO_FEPARAMS) { + result->feparams.frequency = kevent.parameters.frequency; + result->feparams.inversion = lookupval(kevent.parameters.inversion, 1, dvbfe_spectral_inversion_to_kapi); + switch(fehandle->type) { + case FE_QPSK: + result->feparams.u.dvbs.symbol_rate = kevent.parameters.u.qpsk.symbol_rate; + result->feparams.u.dvbs.fec_inner = + lookupval(kevent.parameters.u.qpsk.fec_inner, 1, dvbfe_code_rate_to_kapi); + break; - case FE_ATSC: - result->feparams.u.atsc.modulation = - lookupval(kparams.u.vsb.modulation, 1, dvbfe_atsc_mod_to_kapi); - break; - } - } + case FE_QAM: + result->feparams.u.dvbc.symbol_rate = kevent.parameters.u.qam.symbol_rate; + result->feparams.u.dvbc.fec_inner = + lookupval(kevent.parameters.u.qam.fec_inner, 1, dvbfe_code_rate_to_kapi); + result->feparams.u.dvbc.modulation = + lookupval(kevent.parameters.u.qam.modulation, 1, dvbfe_dvbc_mod_to_kapi); + break; + + case FE_OFDM: + result->feparams.u.dvbt.bandwidth = + lookupval(kevent.parameters.u.ofdm.bandwidth, 1, dvbfe_dvbt_bandwidth_to_kapi); + result->feparams.u.dvbt.code_rate_HP = + lookupval(kevent.parameters.u.ofdm.code_rate_HP, 1, dvbfe_code_rate_to_kapi); + result->feparams.u.dvbt.code_rate_LP = + lookupval(kevent.parameters.u.ofdm.code_rate_LP, 1, dvbfe_code_rate_to_kapi); + result->feparams.u.dvbt.constellation = + lookupval(kevent.parameters.u.ofdm.constellation, 1, dvbfe_dvbt_const_to_kapi); + result->feparams.u.dvbt.transmission_mode = + lookupval(kevent.parameters.u.ofdm.transmission_mode, 1, dvbfe_dvbt_transmit_mode_to_kapi); + result->feparams.u.dvbt.guard_interval = + lookupval(kevent.parameters.u.ofdm.guard_interval, 1, dvbfe_dvbt_guard_interval_to_kapi); + result->feparams.u.dvbt.hierarchy_information = + lookupval(kevent.parameters.u.ofdm.hierarchy_information, 1, dvbfe_dvbt_hierarchy_to_kapi); + break; + case FE_ATSC: + result->feparams.u.atsc.modulation = + lookupval(kevent.parameters.u.vsb.modulation, 1, dvbfe_atsc_mod_to_kapi); + break; + } } + if (querymask & DVBFE_INFO_BER) { if (!ioctl(fehandle->fd, FE_READ_BER, &result->ber)) returnval |= DVBFE_INFO_BER; @@ -324,24 +344,15 @@ int dvbfe_get_info(dvbfe_handle_t _fehandle, dvbfe_info_mask_t querymask, struct returnval |= DVBFE_INFO_UNCORRECTED_BLOCKS; } - // setup for next poll - gettimeofday(&fehandle->nextinfotime, NULL); - fehandle->nextinfotime.tv_usec += GET_INFO_MIN_DELAY_US; - if (fehandle->nextinfotime.tv_usec >= 1000000) { - fehandle->nextinfotime.tv_usec -= 1000000; - fehandle->nextinfotime.tv_sec++; - } - memcpy(&fehandle->cachedinfo, result, sizeof(struct dvbfe_info)); - fehandle->cachedreturnval = returnval; - // done return returnval; } -int dvbfe_set(dvbfe_handle_t _fehandle, struct dvbfe_parameters *params, int timeout) +int dvbfe_set(struct dvbfe_handle *fehandle, + struct dvbfe_parameters *params, + int timeout) { struct dvb_frontend_parameters kparams; - struct dvbfe_handle_prv *fehandle = (struct dvbfe_handle_prv*) _fehandle; int res; struct timeval endtime; fe_status_t status; @@ -428,320 +439,123 @@ int dvbfe_set(dvbfe_handle_t _fehandle, struct dvbfe_parameters *params, int tim return -ETIMEDOUT; } -void dvbfe_poll(dvbfe_handle_t fehandle) +int dvbfe_get_pollfd(struct dvbfe_handle *handle) { - // no implementation required yet + return handle->fd; } +int dvbfe_set_22k_tone(struct dvbfe_handle *fehandle, enum dvbfe_sec_tone_mode tone) +{ + int ret = 0; + switch (tone) { + case DVBFE_SEC_TONE_OFF: + ret = ioctl(fehandle->fd, FE_SET_TONE, SEC_TONE_OFF); + break; + case DVBFE_SEC_TONE_ON: + ret = ioctl(fehandle->fd, FE_SET_TONE, SEC_TONE_ON); + break; + default: + print(verbose, ERROR, 1, "Invalid command !"); + break; + } + if (ret == -1) + print(verbose, ERROR, 1, "IOCTL failed !"); + return ret; +} - - - -int dvbfe_diseqc_command(dvbfe_handle_t _fehandle, char *command) +int dvbfe_set_tone_data_burst(struct dvbfe_handle *fehandle, enum dvbfe_sec_mini_cmd minicmd) { - int i = 0; - int waittime; - int status; - struct dvb_diseqc_master_cmd master_cmd; - unsigned int tmpcmd[6]; - struct dvbfe_handle_prv *fehandle = (struct dvbfe_handle_prv*) _fehandle; - char value_s[20]; - int value_i; - int addr; - - while(command[i]) { - /* kill whitespace */ - if (isspace(command[i])) { - i++; - continue; - } + int ret = 0; - switch(command[i]) { - case 't': - if ((status = ioctl(fehandle->fd, FE_SET_TONE, SEC_TONE_OFF)) != 0) - return status; - break; - - case 'T': - if ((status = ioctl(fehandle->fd, FE_SET_TONE, SEC_TONE_ON)) != 0) - return status; - break; - - case '_': - if ((status = ioctl(fehandle->fd, FE_SET_VOLTAGE, SEC_VOLTAGE_OFF)) != 0) - return status; - break; + switch (minicmd) { + case DVBFE_SEC_MINI_A: + ret = ioctl(fehandle->fd, FE_DISEQC_SEND_BURST, SEC_MINI_A); + break; + case DVBFE_SEC_MINI_B: + ret = ioctl(fehandle->fd, FE_DISEQC_SEND_BURST, SEC_MINI_B); + break; + default: + print(verbose, ERROR, 1, "Invalid command"); + break; + } + if (ret == -1) + print(verbose, ERROR, 1, "IOCTL failed"); - case 'v': - if ((status = ioctl(fehandle->fd, FE_SET_VOLTAGE, SEC_VOLTAGE_13)) != 0) - return status; - break; + return ret; +} - case 'V': - if ((status = ioctl(fehandle->fd, FE_SET_VOLTAGE, SEC_VOLTAGE_18)) != 0) - return status; - break; +int dvbfe_set_voltage(struct dvbfe_handle *fehandle, enum dvbfe_sec_voltage voltage) +{ + int ret = 0; - case 'A': - if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_BURST, SEC_MINI_A)) != 0) - return status; - break; + switch (voltage) { + case DVBFE_SEC_VOLTAGE_OFF: + ret = ioctl(fehandle->fd, FE_SET_VOLTAGE, SEC_VOLTAGE_OFF); + break; + case DVBFE_SEC_VOLTAGE_13: + ret = ioctl(fehandle->fd, FE_SET_VOLTAGE, SEC_VOLTAGE_13); + break; + case DVBFE_SEC_VOLTAGE_18: + ret = ioctl(fehandle->fd, FE_SET_VOLTAGE, SEC_VOLTAGE_18); + break; + default: + print(verbose, ERROR, 1, "Invalid command"); + break; + } + if (ret == -1) + print(verbose, ERROR, 1, "IOCTL failed"); - case 'B': - if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_BURST, SEC_MINI_B)) != 0) - return status; - break; + return ret; +} - case '+': - ioctl(fehandle->fd, FE_ENABLE_HIGH_LNB_VOLTAGE, 1); - /* don't care if this one is not supported */ - break; +int dvbfe_set_high_lnb_voltage(struct dvbfe_handle *fehandle, int on) +{ + switch (on) { + case 0: + ioctl(fehandle->fd, FE_ENABLE_HIGH_LNB_VOLTAGE, 0); + break; + default: + ioctl(fehandle->fd, FE_ENABLE_HIGH_LNB_VOLTAGE, 1); + break; + } + return 0; +} - case '-': - ioctl(fehandle->fd, FE_ENABLE_HIGH_LNB_VOLTAGE, 0); - /* don't care if this one is not supported */ - break; +int dvbfe_do_dishnetworks_legacy_command(struct dvbfe_handle *fehandle, unsigned int cmd) +{ + int ret = 0; - case 'W': - waittime = atoi(command + i + 1); - if (waittime == 0) { - return -EINVAL; - } - usleep(waittime * 1000); - while(command[i] && !isspace(command[i])) - i++; - break; + ret = ioctl(fehandle->fd, FE_DISHNETWORK_SEND_LEGACY_CMD, cmd); + if (ret == -1) + print(verbose, ERROR, 1, "IOCTL failed"); - case '.': // extended command - { - i++; - - if (!strncmp(command+i, "D(", 2)) { - i += 2; - - master_cmd.msg_len = - sscanf(command+i, "%x %x %x %x %x %x", - tmpcmd, tmpcmd+1, tmpcmd+2, tmpcmd+3, tmpcmd+4, tmpcmd+5); - if (master_cmd.msg_len == 0) - return -EINVAL; - master_cmd.msg[0] = tmpcmd[0]; - master_cmd.msg[1] = tmpcmd[1]; - master_cmd.msg[2] = tmpcmd[2]; - master_cmd.msg[3] = tmpcmd[3]; - master_cmd.msg[4] = tmpcmd[4]; - master_cmd.msg[5] = tmpcmd[5]; - - if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0) - return status; - } else if (!strncmp(command+i, "Dband(", 6)) { - if (sscanf(command+i+6, "%i %2s", &addr, value_s) != 2) - return -EINVAL; - if (!strncmp(value_s, "lo", 2)) { - master_cmd.msg[0] = 0xe0; - master_cmd.msg[1] = addr; - master_cmd.msg[2] = 0x20; - master_cmd.msg_len = 3; - } else if (!strncmp(value_s, "hi", 2)) { - master_cmd.msg[0] = 0xe0; - master_cmd.msg[1] = addr; - master_cmd.msg[2] = 0x24; - master_cmd.msg_len = 3; - } else { - return -EINVAL; - } - if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0) - return status; - - } else if ((!strncmp(command+i, "Dpolarisation(", 14) || - (!strncmp(command+i, "Dpolarization(", 14)))) { - if (sscanf(command+i+14, "%i %1s", &addr, value_s) != 2) - return -EINVAL; - switch(*value_s) { - case 'H': - case 'L': - master_cmd.msg[0] = 0xe0; - master_cmd.msg[1] = addr; - master_cmd.msg[2] = 0x25; - master_cmd.msg_len = 3; - break; - - case 'V': - case 'R': - master_cmd.msg[0] = 0xe0; - master_cmd.msg[1] = addr; - master_cmd.msg[2] = 0x21; - master_cmd.msg_len = 3; - break; - - default: - return -EINVAL; - } - if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0) - return status; - - } else if (!strncmp(command+i, "Dsatellite_position(", 20)) { - if (sscanf(command+i+20, "%i %1s", &addr, value_s) != 2) - return -EINVAL; - switch(*value_s) { - case 'A': - case 'C': - master_cmd.msg[0] = 0xe0; - master_cmd.msg[1] = addr; - master_cmd.msg[2] = 0x22; - master_cmd.msg_len = 3; - break; - - case 'B': - case 'D': - master_cmd.msg[0] = 0xe0; - master_cmd.msg[1] = addr; - master_cmd.msg[2] = 0x26; - master_cmd.msg_len = 3; - break; - - default: - return -EINVAL; - } - if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0) - return status; - - } else if (!strncmp(command+i, "Dswitch_option(", 15)) { - if (sscanf(command+i+15, "%i %1s", &addr, value_s) != 2) - return -EINVAL; - switch(*value_s) { - case 'A': - master_cmd.msg[0] = 0xe0; - master_cmd.msg[1] = addr; - master_cmd.msg[2] = 0x23; - master_cmd.msg_len = 3; - break; - - case 'B': - master_cmd.msg[0] = 0xe0; - master_cmd.msg[1] = addr; - master_cmd.msg[2] = 0x27; - master_cmd.msg_len = 3; - break; - - default: - return -EINVAL; - } - if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0) - return status; - - } else if (!strncmp(command+i, "Dport_pins(", 11)) { - int mask; - if (sscanf(command+i+11, "%i %i %i", &addr, &mask, &value_i) != 3) - return -EINVAL; - - if (mask & 0x0f) { - master_cmd.msg[0] = 0xe0; - master_cmd.msg[1] = addr; - master_cmd.msg[2] = 0x38; - master_cmd.msg[3] = ((mask & 0x0f) << 4) | (value_i & 0x0f); - master_cmd.msg_len = 4; - - if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0) - return status; - } - if (mask & 0xf0) { - master_cmd.msg[0] = 0xe0; - master_cmd.msg[1] = addr; - master_cmd.msg[2] = 0x39; - master_cmd.msg[3] = (mask & 0xf0) | ((value_i & 0xf0) >> 4); - master_cmd.msg_len = 4; - - if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0) - return status; - } - - } else if (!strncmp(command+i, "Dgoto_preset(", 13)) { - if (sscanf(command+i+13, "%i %i", &addr, &value_i) != 2) - return -EINVAL; - - master_cmd.msg[0] = 0xe0; - master_cmd.msg[1] = addr; - master_cmd.msg[2] = 0x3b; - master_cmd.msg[3] = value_i; - master_cmd.msg_len = 4; - - if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0) - return status; - - } else if (!strncmp(command+i, "Dgoto_angle(", 12)) { - int integer = 0; - int fraction = 0; - char *tmp; - - if (sscanf(command+i+12, "%i %s", &addr, value_s) != 2) - return -EINVAL; - - // parse the integer and fractional parts using fixed point - integer = atoi(value_s); - tmp = strchr(value_s, '.'); - if (tmp != NULL) { - tmp++; - tmp[3] = 0; - fraction = ((atoi(tmp) * 16000) / 1000000) & 0xf; - } - - // generate the command - master_cmd.msg[0] = 0xe0; - master_cmd.msg[1] = addr; - master_cmd.msg[2] = 0x6e; - if (integer < -256) { - return -EINVAL; - } else if (integer < 0) { - integer = -integer; - master_cmd.msg[3] = 0xf0; - } else if (integer < 256) { - master_cmd.msg[3] = 0x00; - } else if (integer < 512) { - integer -= 256; - master_cmd.msg[3] = 0x10; - } else { - return -EINVAL; - } - master_cmd.msg[3] |= ((integer / 16) & 0x0f); - integer = integer % 16; - master_cmd.msg[4] |= ((integer & 0x0f) << 4) | fraction; - master_cmd.msg_len = 5; - - if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0) - return status; - - } else if (!strncmp(command+i, "dishnetworks(", 13)) { - if (sscanf(command+i+13, "%i", tmpcmd) != 1) - return -EINVAL; - - if ((status = ioctl(fehandle->fd, FE_DISHNETWORK_SEND_LEGACY_CMD, tmpcmd)) != 0) - return status; - } + return ret; +} - /* skip to the end... */ - while(command[i] && (command[i] != ')')) - i++; - break; - } +int dvbfe_do_diseqc_command(struct dvbfe_handle *fehandle, uint8_t *data, uint8_t len) +{ + int ret = 0; + struct dvb_diseqc_master_cmd diseqc_message; + if (len > 6) + return -EINVAL; - default: - return -EINVAL; - } + diseqc_message.msg_len = len; + memcpy(diseqc_message.msg, data, len); - i++; - } + ret = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &diseqc_message); + if (ret == -1) + print(verbose, ERROR, 1, "IOCTL failed"); - return 0; + return ret; } -int dvbfe_diseqc_read(dvbfe_handle_t _fehandle, int timeout, unsigned char *buf, unsigned int len) +int dvbfe_diseqc_read(struct dvbfe_handle *fehandle, int timeout, unsigned char *buf, unsigned int len) { struct dvb_diseqc_slave_reply reply; int result; - struct dvbfe_handle_prv *fehandle = (struct dvbfe_handle_prv*) _fehandle; if (len > 4) len = 4; diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/dvbfe.h b/kaffeine/src/input/dvb/lib/libdvbapi/dvbfe.h index 9eb03b7..69cb05b 100644 --- a/kaffeine/src/input/dvb/lib/libdvbapi/dvbfe.h +++ b/kaffeine/src/input/dvb/lib/libdvbapi/dvbfe.h @@ -2,6 +2,7 @@ * libdvbfe - a DVB frontend library * * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * Copyright (C) 2005 Manu Abraham <abraham.manu@gmail.com> * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) * * This library is free software; you can redistribute it and/or @@ -32,27 +33,20 @@ extern "C" /** * The types of frontend we support. */ -typedef enum dvbfe_type { +enum dvbfe_type { DVBFE_TYPE_DVBS, DVBFE_TYPE_DVBC, DVBFE_TYPE_DVBT, DVBFE_TYPE_ATSC, -} dvbfe_type_t; - -typedef enum dvbfe_polarization { - DVBFE_POLARIZATION_H, - DVBFE_POLARIZATION_V, - DVBFE_POLARIZATION_L, - DVBFE_POLARIZATION_R, -} dvbfe_polarization_t; +}; -typedef enum dvbfe_spectral_inversion { +enum dvbfe_spectral_inversion { DVBFE_INVERSION_OFF, DVBFE_INVERSION_ON, DVBFE_INVERSION_AUTO -} dvbfe_spectral_inversion_t; +}; -typedef enum dvbfe_code_rate { +enum dvbfe_code_rate { DVBFE_FEC_NONE, DVBFE_FEC_1_2, DVBFE_FEC_2_3, @@ -63,9 +57,9 @@ typedef enum dvbfe_code_rate { DVBFE_FEC_7_8, DVBFE_FEC_8_9, DVBFE_FEC_AUTO -} dvbfe_code_rate_t; +}; -typedef enum dvbfe_dvbt_const { +enum dvbfe_dvbt_const { DVBFE_DVBT_CONST_QPSK, DVBFE_DVBT_CONST_QAM_16, DVBFE_DVBT_CONST_QAM_32, @@ -73,106 +67,121 @@ typedef enum dvbfe_dvbt_const { DVBFE_DVBT_CONST_QAM_128, DVBFE_DVBT_CONST_QAM_256, DVBFE_DVBT_CONST_AUTO -} dvbfe_dvbt_const_t; +}; -typedef enum dvbfe_dvbc_mod { +enum dvbfe_dvbc_mod { DVBFE_DVBC_MOD_QAM_16, DVBFE_DVBC_MOD_QAM_32, DVBFE_DVBC_MOD_QAM_64, DVBFE_DVBC_MOD_QAM_128, DVBFE_DVBC_MOD_QAM_256, DVBFE_DVBC_MOD_AUTO, -} dvbfe_dvbc_mod_t; +}; -typedef enum dvbfe_atsc_mod { +enum dvbfe_atsc_mod { DVBFE_ATSC_MOD_QAM_64, DVBFE_ATSC_MOD_QAM_256, DVBFE_ATSC_MOD_VSB_8, DVBFE_ATSC_MOD_VSB_16, DVBFE_ATSC_MOD_AUTO -} dvbfe_atsc_mod_t; +}; -typedef enum dvbfe_dvbt_transmit_mode { +enum dvbfe_dvbt_transmit_mode { DVBFE_DVBT_TRANSMISSION_MODE_2K, DVBFE_DVBT_TRANSMISSION_MODE_8K, DVBFE_DVBT_TRANSMISSION_MODE_AUTO -} dvbfe_dvbt_transmit_mode_t; +}; -typedef enum dvbfe_dvbt_bandwidth { +enum dvbfe_dvbt_bandwidth { DVBFE_DVBT_BANDWIDTH_8_MHZ, DVBFE_DVBT_BANDWIDTH_7_MHZ, DVBFE_DVBT_BANDWIDTH_6_MHZ, DVBFE_DVBT_BANDWIDTH_AUTO -} dvbfe_dvbt_bandwidth_t; +}; -typedef enum dvbfe_dvbt_guard_interval { +enum dvbfe_dvbt_guard_interval { DVBFE_DVBT_GUARD_INTERVAL_1_32, DVBFE_DVBT_GUARD_INTERVAL_1_16, DVBFE_DVBT_GUARD_INTERVAL_1_8, DVBFE_DVBT_GUARD_INTERVAL_1_4, DVBFE_DVBT_GUARD_INTERVAL_AUTO -} dvbfe_dvbt_guard_interval_t; +}; -typedef enum dvbfe_dvbt_hierarchy { +enum dvbfe_dvbt_hierarchy { DVBFE_DVBT_HIERARCHY_NONE, DVBFE_DVBT_HIERARCHY_1, DVBFE_DVBT_HIERARCHY_2, DVBFE_DVBT_HIERARCHY_4, DVBFE_DVBT_HIERARCHY_AUTO -} dvbfe_dvbt_hierarchy_t; +}; /** * Structure used to store and communicate frontend parameters. */ struct dvbfe_parameters { uint32_t frequency; - dvbfe_spectral_inversion_t inversion; + enum dvbfe_spectral_inversion inversion; union { struct { uint32_t symbol_rate; - dvbfe_code_rate_t fec_inner; - dvbfe_polarization_t polarization; + enum dvbfe_code_rate fec_inner; } dvbs; struct { uint32_t symbol_rate; - dvbfe_code_rate_t fec_inner; - dvbfe_dvbc_mod_t modulation; + enum dvbfe_code_rate fec_inner; + enum dvbfe_dvbc_mod modulation; } dvbc; struct { - dvbfe_dvbt_bandwidth_t bandwidth; - dvbfe_code_rate_t code_rate_HP; - dvbfe_code_rate_t code_rate_LP; - dvbfe_dvbt_const_t constellation; - dvbfe_dvbt_transmit_mode_t transmission_mode; - dvbfe_dvbt_guard_interval_t guard_interval; - dvbfe_dvbt_hierarchy_t hierarchy_information; + enum dvbfe_dvbt_bandwidth bandwidth; + enum dvbfe_code_rate code_rate_HP; + enum dvbfe_code_rate code_rate_LP; + enum dvbfe_dvbt_const constellation; + enum dvbfe_dvbt_transmit_mode transmission_mode; + enum dvbfe_dvbt_guard_interval guard_interval; + enum dvbfe_dvbt_hierarchy hierarchy_information; } dvbt; struct { - dvbfe_atsc_mod_t modulation; + enum dvbfe_atsc_mod modulation; } atsc; } u; }; +enum dvbfe_sec_voltage { + DVBFE_SEC_VOLTAGE_13, + DVBFE_SEC_VOLTAGE_18, + DVBFE_SEC_VOLTAGE_OFF +}; + +enum dvbfe_sec_tone_mode { + DVBFE_SEC_TONE_ON, + DVBFE_SEC_TONE_OFF +}; + +enum dvbfe_sec_mini_cmd { + DVBFE_SEC_MINI_A, + DVBFE_SEC_MINI_B +}; + /** * Mask of values used in the dvbfe_get_info() call. */ -typedef enum dvbfe_info_mask { +enum dvbfe_info_mask { DVBFE_INFO_LOCKSTATUS = 0x01, DVBFE_INFO_FEPARAMS = 0x02, DVBFE_INFO_BER = 0x04, DVBFE_INFO_SIGNAL_STRENGTH = 0x08, DVBFE_INFO_SNR = 0x10, DVBFE_INFO_UNCORRECTED_BLOCKS = 0x20, -} dvbfe_info_mask_t; +}; /** * Structure containing values used by the dvbfe_get_info() call. */ struct dvbfe_info { - dvbfe_type_t type; /* always retrieved */ + enum dvbfe_type type; /* always retrieved */ const char *name; /* always retrieved */ unsigned int signal : 1; /* } DVBFE_INFO_LOCKSTATUS */ unsigned int carrier : 1; /* } */ @@ -187,9 +196,23 @@ struct dvbfe_info { }; /** + * Possible types of query used in dvbfe_get_info. + * + * DVBFE_INFO_QUERYTYPE_IMMEDIATE - interrogate frontend for most up to date values. + * DVBFE_INFO_QUERYTYPE_LOCKCHANGE - return details from queued lock status + * change events, or wait for one to occur + * if none are queued. + */ +enum dvbfe_info_querytype { + DVBFE_INFO_QUERYTYPE_IMMEDIATE, + DVBFE_INFO_QUERYTYPE_LOCKCHANGE, +}; + + +/** * Frontend handle datatype. */ -typedef void *dvbfe_handle_t; +struct dvbfe_handle; /** * Open a DVB frontend. @@ -199,18 +222,21 @@ typedef void *dvbfe_handle_t; * @param readonly If 1, frontend will be opened in readonly mode only. * @return A handle on success, or NULL on failure. */ -extern dvbfe_handle_t dvbfe_open(int adapter, int frontend, int readonly); +extern struct dvbfe_handle *dvbfe_open(int adapter, int frontend, int readonly); /** * Close a DVB frontend. * * @param fehandle Handle opened with dvbfe_open(). */ -extern void dvbfe_close(dvbfe_handle_t handle); +extern void dvbfe_close(struct dvbfe_handle *handle); /** * Set the frontend tuning parameters. * + * Note: this function provides only the basic tuning operation; you might want to + * investigate dvbfe_set_sec() in sec.h for a unified device tuning operation. + * * @param fehandle Handle opened with dvbfe_open(). * @param params Params to set. * @param timeout <0 => wait forever for lock. 0=>return immediately, >0=> @@ -218,14 +244,9 @@ extern void dvbfe_close(dvbfe_handle_t handle); * @return 0 on locked (or if timeout==0 and everything else worked), or * nonzero on failure (including no lock). */ -extern int dvbfe_set(dvbfe_handle_t fehandle, struct dvbfe_parameters *params, int timeout); - -/** - * Call this function regularly from a loop to maintain the frontend lock. - * - * @param fehandle Handle opened with dvbfe_open(). - */ -extern void dvbfe_poll(dvbfe_handle_t fehandle); +extern int dvbfe_set(struct dvbfe_handle *fehandle, + struct dvbfe_parameters *params, + int timeout); /** * Retrieve information about the frontend. @@ -233,62 +254,66 @@ extern void dvbfe_poll(dvbfe_handle_t fehandle); * @param fehandle Handle opened with dvbfe_open(). * @param querymask ORed bitmask of desired DVBFE_INFO_* values. * @param result Where to put the retrieved results. + * @param querytype Type of query requested. + * @param timeout Timeout in ms to use if querytype==lockchange (0=>no timeout, <0=> wait forever). * @return ORed bitmask of DVBFE_INFO_* indicating which values were read successfully. */ -extern int dvbfe_get_info(dvbfe_handle_t fehandle, dvbfe_info_mask_t querymask, struct dvbfe_info *result); +extern int dvbfe_get_info(struct dvbfe_handle *fehandle, + enum dvbfe_info_mask querymask, + struct dvbfe_info *result, + enum dvbfe_info_querytype querytype, + int timeout); /** - * Execute a DISEQC command string. - * - * A diseqc command consists of a sequence of the following codes, separated by - * whitespace: - * Simple commands: - * t - turn 22kHz tone off. - * T - turn 22kHz tone on. - * _ - set voltage to 0v (i.e. off). - * v - set voltage to 13v. - * V - set voltage to 18v. - * + - Enable high LNB voltage. - * - - Disable high LNB voltage. - * A - send DISEQC mini command A. - * B - send DISEQC mini command B. - * Wii - Delay for ii milliseconds. - * - * Extended commands: - * .dishnetworks(<value>) - Send a dish networks legacy command <value> - * .D(<value> ...) - Send a raw diseqc master command. The command may be up - * to 6 bytes long. - * .Dband(<addr> <lo|hi>) - Set frequency band hi or lo. - * .Dpolarisation(<addr> <V|H|L|R>) - Set polarisation. - * .Dsatellite_position(<addr> <A|B>) - Set "satellite position" input switch. - * .Dswitch_option(<addr> <A|B>) - Set "switch option" input switch. - * .Dport_pins(<addr> <mask> <value>) - Set all input switches. Mask and value - * are hex-ascii 8 bit bytes. Only bits with a corresponding '1' in mask - * will be changed. - * .Dgoto_preset(<addr> <index>) - Set a positioner to a preset index (integer) - * .Dgoto_angle(<addr> <angle>) - Set a positioner to a given angle - * (e.g. 49.6). The angle may range between -180 to 496. It may include a - * fractional part. - * - * All integer values use standard notation - no prefix=>decimal, 0x=>hex etc. - * - * Set <addr> to 0 if you just have a simple DISEQC setup (e.g. one switch). See - * the DISEQC specification at http://www.eutelsat.org/ for full information. - * - * Comments begin with '#' - any characters after this will be ignored - * to the end of the line. - * - * Examples: - * S-19.2E 11700000 V 9750000 t v W15 .D(E0 10 38 F0) W15 A W15 t - * S-19.2E 99999999 V 10600000 t v W15 .D(E0 10 38 F1) W15 A W15 T - * S-19.2E 11700000 H 9750000 t V W15 .D(E0 10 38 F2) W15 A W15 t - * S-19.2E 99999999 H 10600000 t V W15 .D(E0 10 38 F3) W15 A W15 T + * Get a file descriptor for polling for lock status changes. * * @param fehandle Handle opened with dvbfe_open(). - * @param command Command to execute. - * @return 0 on success, nonzero on failure. + * @return FD for polling. + */ +extern int dvbfe_get_pollfd(struct dvbfe_handle *handle); + +/** + * Tone/Data Burst control + * @param fehandle Handle opened with dvbfe_open(). + * @param tone, SEC_TONE_ON/SEC_TONE_OFF + */ +extern int dvbfe_set_22k_tone(struct dvbfe_handle *handle, enum dvbfe_sec_tone_mode tone); + +/** + * 22khz Tone control + * @param fehandle Handle opened with dvbfe_open(). + * @param adapter, minicmd, SEC_MINI_A/SEC_MINI_B + */ +extern int dvbfe_set_tone_data_burst(struct dvbfe_handle *handle, enum dvbfe_sec_mini_cmd minicmd); + +/** + * Voltage control + * @param fehandle Handle opened with dvbfe_open(). + * @param polarization, SEC_VOLTAGE_13/SEC_VOLTAGE_18/SEC_VOLTAGE_OFF + */ +extern int dvbfe_set_voltage(struct dvbfe_handle *handle, enum dvbfe_sec_voltage voltage); + +/** + * High LNB voltage control (increases voltage by 1v to compensate for long cables) + * @param fehandle Handle opened with dvbfe_open(). + * @param on 1 to enable, 0 to disable. + */ +extern int dvbfe_set_high_lnb_voltage(struct dvbfe_handle *fehandle, int on); + +/** + * Send a legacy Dish Networks command + * @param fehandle Handle opened with dvbfe_open(). + * @param cmd, the command to send + */ +extern int dvbfe_do_dishnetworks_legacy_command(struct dvbfe_handle *handle, unsigned int cmd); + +/** + * Send a DiSEqC Command + * @param fehandle Handle opened with dvbfe_open(). + * @param data, a pointer to am array containing the data to be sent. + * @param len Length of data in bytes, max 6 bytes. */ -extern int dvbfe_diseqc_command(dvbfe_handle_t fehandle, char *command); +extern int dvbfe_do_diseqc_command(struct dvbfe_handle *handle, uint8_t *data, uint8_t len); /** * Read a DISEQC response from the frontend. @@ -299,7 +324,7 @@ extern int dvbfe_diseqc_command(dvbfe_handle_t fehandle, char *command); * @param len Number of bytes in buffer. * @return >= 0 on success (number of received bytes), <0 on failure. */ -extern int dvbfe_diseqc_read(dvbfe_handle_t fehandle, int timeout, unsigned char *buf, unsigned int len); +extern int dvbfe_diseqc_read(struct dvbfe_handle *fehandle, int timeout, unsigned char *buf, unsigned int len); #ifdef __cplusplus } diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/dvbnet.c b/kaffeine/src/input/dvb/lib/libdvbapi/dvbnet.c index d6ee632..f0f08f9 100644 --- a/kaffeine/src/input/dvb/lib/libdvbapi/dvbnet.c +++ b/kaffeine/src/input/dvb/lib/libdvbapi/dvbnet.c @@ -44,9 +44,10 @@ int dvbnet_open(int adapter, int netdeviceid) return fd; } -int dvbnet_add_interface(int fd, uint16_t pid, int encapsulation) +int dvbnet_add_interface(int fd, uint16_t pid, enum dvbnet_encap encapsulation) { struct dvb_net_if params; + int status; memset(¶ms, 0, sizeof(params)); params.pid = pid; @@ -63,10 +64,14 @@ int dvbnet_add_interface(int fd, uint16_t pid, int encapsulation) default: return -EINVAL; } - return ioctl(fd, NET_ADD_IF, ¶ms); + + status = ioctl(fd, NET_ADD_IF, ¶ms); + if (status < 0) + return status; + return params.if_num; } -int dvbnet_get_interface(int fd, int ifnum, uint16_t *pid, int *encapsulation) +int dvbnet_get_interface(int fd, int ifnum, uint16_t *pid, enum dvbnet_encap *encapsulation) { struct dvb_net_if info; int res; diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/dvbnet.h b/kaffeine/src/input/dvb/lib/libdvbapi/dvbnet.h index 426e540..287919f 100644 --- a/kaffeine/src/input/dvb/lib/libdvbapi/dvbnet.h +++ b/kaffeine/src/input/dvb/lib/libdvbapi/dvbnet.h @@ -31,10 +31,10 @@ extern "C" /** * Possible encapsulations of data. */ -typedef enum dvbnet_encap { +enum dvbnet_encap { DVBNET_ENCAP_MPE, DVBNET_ENCAP_ULE, -} dvbnet_encap_t; +}; /** * The maximum allowed number of dvb network devices per adapter netdevice. @@ -56,9 +56,9 @@ extern int dvbnet_open(int adapter, int netdeviceid); * @param fd FD opened with libdvbnet_open(). * @param pid PID of the stream containing the network data. * @param encapsulation Encapsulation type of the stream (one of DVBNET_ENCAP_*). - * @return 0 on success, nonzero on failure. + * @return Index of new interface on success, < 0 on failure. */ -extern int dvbnet_add_interface(int fd, uint16_t pid, int encapsulation); +extern int dvbnet_add_interface(int fd, uint16_t pid, enum dvbnet_encap encapsulation); /** * Get details of a DVBNET interface. @@ -69,7 +69,7 @@ extern int dvbnet_add_interface(int fd, uint16_t pid, int encapsulation); * @param encapsulation The encapsulation of the interface (DVBNET_ENCAP_*). * @return 0 on success, nonzero on failure. */ -extern int dvbnet_get_interface(int fd, int ifnum, uint16_t *pid, int *encapsulation); +extern int dvbnet_get_interface(int fd, int ifnum, uint16_t *pid, enum dvbnet_encap *encapsulation); /** * Remove a DVBNET interface. diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/dvbvideo.c b/kaffeine/src/input/dvb/lib/libdvbapi/dvbvideo.c new file mode 100644 index 0000000..f1ffbe8 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvbapi/dvbvideo.c @@ -0,0 +1,46 @@ +/* + * libdvbnet - a DVB network support library + * + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <sys/param.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <linux/types.h> +#include <linux/dvb/video.h> +#include <errno.h> +#include "dvbvideo.h" + +int dvbvideo_open(int adapter, int videodeviceid) +{ + char filename[PATH_MAX+1]; + int fd; + + sprintf(filename, "/dev/dvb/adapter%i/video%i", adapter, videodeviceid); + if ((fd = open(filename, O_RDWR)) < 0) { + // if that failed, try a flat /dev structure + sprintf(filename, "/dev/dvb%i.video%i", adapter, videodeviceid); + fd = open(filename, O_RDWR); + } + + return fd; +} diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/dvbvideo.h b/kaffeine/src/input/dvb/lib/libdvbapi/dvbvideo.h new file mode 100644 index 0000000..cc49914 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvbapi/dvbvideo.h @@ -0,0 +1,46 @@ +/* + * libdvbnet - a DVB network support library + * + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef LIBDVBVIDEO_H +#define LIBDVBVIDEO_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdint.h> + +/** + * Open a DVB video device. + * + * @param adapter DVB adapter ID. + * @param videodeviceid Id of video device of that adapter to open. + * @return A unix file descriptor on success, or -1 on failure. + */ +extern int dvbvideo_open(int adapter, int videodeviceid); + +// FIXME: this is a stub library + +#ifdef __cplusplus +} +#endif + +#endif // LIBDVBVIDEO_H diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/Makefile.am b/kaffeine/src/input/dvb/lib/libdvben50221/Makefile.am index 7c9764a..6942c02 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/Makefile.am +++ b/kaffeine/src/input/dvb/lib/libdvben50221/Makefile.am @@ -16,6 +16,9 @@ libdvben50221_la_SOURCES = asn_1.c \ en50221_app_teletext.c \ en50221_app_utils.c \ en50221_session.c \ - en50221_transport.c + en50221_transport.c \ + en50221_stdcam.c \ + en50221_stdcam_llci.c \ + en50221_stdcam_hlci.c CFLAGS = -g -O2 -DLOG_LEVEL=1 -Wall -Wshadow -Wpointer-arith -Wstrict-prototypes -fPIC diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/asn_1.c b/kaffeine/src/input/dvb/lib/libdvben50221/asn_1.c index 0c6ff5c..803eb60 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/asn_1.c +++ b/kaffeine/src/input/dvb/lib/libdvben50221/asn_1.c @@ -2,8 +2,8 @@ ASN.1 routines, implementation for libdvben50221 an implementation for the High Level Common Interface - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) - Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as @@ -17,65 +17,67 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <stdio.h> #include "asn_1.h" -int asn_1_decode(uint16_t *length, uint8_t *asn_1_array, uint32_t asn_1_array_len) +int asn_1_decode(uint16_t * length, uint8_t * asn_1_array, + uint32_t asn_1_array_len) { uint8_t length_field; - if (asn_1_array_len < 1) - return -1; + if (asn_1_array_len < 1) + return -1; length_field = asn_1_array[0]; - if (length_field < 0x80) { + if (length_field < 0x80) { // there is only one word *length = length_field & 0x7f; - return 1; - } else if (length_field == 0x81) { - if (asn_1_array_len < 2) - return -1; - - *length = asn_1_array[1]; - return 2; - } else if (length_field == 0x82) { - if (asn_1_array_len < 3) - return -1; - - *length = (asn_1_array[1] << 8) | asn_1_array[2]; - return 3; - } - - return -1; + return 1; + } else if (length_field == 0x81) { + if (asn_1_array_len < 2) + return -1; + + *length = asn_1_array[1]; + return 2; + } else if (length_field == 0x82) { + if (asn_1_array_len < 3) + return -1; + + *length = (asn_1_array[1] << 8) | asn_1_array[2]; + return 3; + } + + return -1; } -int asn_1_encode(uint16_t length, uint8_t *asn_1_array, uint32_t asn_1_array_len) +int asn_1_encode(uint16_t length, uint8_t * asn_1_array, + uint32_t asn_1_array_len) { - if (length < 0x80) { - if (asn_1_array_len < 1) - return -1; + if (length < 0x80) { + if (asn_1_array_len < 1) + return -1; - asn_1_array[0] = length & 0x7f; - return 1; + asn_1_array[0] = length & 0x7f; + return 1; } else if (length < 0x100) { - if (asn_1_array_len < 2) - return -1; - - asn_1_array[0] = 0x81; - asn_1_array[1] = length; - return 2; - } else { - if (asn_1_array_len < 3) - return -1; - - asn_1_array[0] = 0x82; - asn_1_array[1] = length >> 8; - asn_1_array[2] = length; - return 3; + if (asn_1_array_len < 2) + return -1; + + asn_1_array[0] = 0x81; + asn_1_array[1] = length; + return 2; + } else { + if (asn_1_array_len < 3) + return -1; + + asn_1_array[0] = 0x82; + asn_1_array[1] = length >> 8; + asn_1_array[2] = length; + return 3; } - // never reached + // never reached } diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/asn_1.h b/kaffeine/src/input/dvb/lib/libdvben50221/asn_1.h index bae6da8..c8774db 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/asn_1.h +++ b/kaffeine/src/input/dvb/lib/libdvben50221/asn_1.h @@ -2,8 +2,8 @@ ASN.1 routines, implementation for libdvben50221 an implementation for the High Level Common Interface - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) - Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as @@ -17,25 +17,25 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __ASN_1_H__ #define __ASN_1_H__ #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif #include <stdlib.h> #include <stdint.h> -int asn_1_decode(uint16_t *length, uint8_t *asn_1_array, uint32_t asn_1_array_len); -int asn_1_encode(uint16_t length, uint8_t *asn_1_array, uint32_t asn_1_array_len); +int asn_1_decode(uint16_t * length, uint8_t * asn_1_array, + uint32_t asn_1_array_len); +int asn_1_encode(uint16_t length, uint8_t * asn_1_array, + uint32_t asn_1_array_len); #ifdef __cplusplus } #endif - #endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ai.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ai.c index e3e73ab..b7ded66 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ai.c +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ai.c @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,7 +18,7 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <string.h> @@ -28,106 +28,107 @@ #include "en50221_app_tags.h" #include "asn_1.h" -struct en50221_app_ai_private { - struct en50221_app_send_functions *funcs; +struct en50221_app_ai { + struct en50221_app_send_functions *funcs; - en50221_app_ai_callback callback; - void *callback_arg; + en50221_app_ai_callback callback; + void *callback_arg; - pthread_mutex_t lock; + pthread_mutex_t lock; }; -static int en50221_app_ai_parse_app_info(struct en50221_app_ai_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length); +static int en50221_app_ai_parse_app_info(struct en50221_app_ai *ai, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length); -en50221_app_ai en50221_app_ai_create(struct en50221_app_send_functions *funcs) +struct en50221_app_ai *en50221_app_ai_create(struct en50221_app_send_functions *funcs) { - struct en50221_app_ai_private *private = NULL; + struct en50221_app_ai *ai = NULL; - // create structure and set it up - private = malloc(sizeof(struct en50221_app_ai_private)); - if (private == NULL) { - return NULL; - } - private->funcs = funcs; - private->callback = NULL; + // create structure and set it up + ai = malloc(sizeof(struct en50221_app_ai)); + if (ai == NULL) { + return NULL; + } + ai->funcs = funcs; + ai->callback = NULL; - pthread_mutex_init(&private->lock, NULL); + pthread_mutex_init(&ai->lock, NULL); - // done - return private; + // done + return ai; } -void en50221_app_ai_destroy(en50221_app_ai ai) +void en50221_app_ai_destroy(struct en50221_app_ai *ai) { - struct en50221_app_ai_private *private = (struct en50221_app_ai_private *) ai; - - pthread_mutex_destroy(&private->lock); - free(private); + pthread_mutex_destroy(&ai->lock); + free(ai); } -void en50221_app_ai_register_callback(en50221_app_ai ai, en50221_app_ai_callback callback, void *arg) +void en50221_app_ai_register_callback(struct en50221_app_ai *ai, + en50221_app_ai_callback callback, + void *arg) { - struct en50221_app_ai_private *private = (struct en50221_app_ai_private *) ai; - - pthread_mutex_lock(&private->lock); - private->callback = callback; - private->callback_arg = arg; - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&ai->lock); + ai->callback = callback; + ai->callback_arg = arg; + pthread_mutex_unlock(&ai->lock); } -int en50221_app_ai_enquiry(en50221_app_ai ai, uint16_t session_number) +int en50221_app_ai_enquiry(struct en50221_app_ai *ai, + uint16_t session_number) { - struct en50221_app_ai_private *private = (struct en50221_app_ai_private *) ai; - uint8_t data[4]; + uint8_t data[4]; - data[0] = (TAG_APP_INFO_ENQUIRY >> 16) & 0xFF; - data[1] = (TAG_APP_INFO_ENQUIRY >> 8) & 0xFF; - data[2] = TAG_APP_INFO_ENQUIRY & 0xFF; - data[3] = 0; + data[0] = (TAG_APP_INFO_ENQUIRY >> 16) & 0xFF; + data[1] = (TAG_APP_INFO_ENQUIRY >> 8) & 0xFF; + data[2] = TAG_APP_INFO_ENQUIRY & 0xFF; + data[3] = 0; - return private->funcs->send_data(private->funcs->arg, session_number, data, 4); + return ai->funcs->send_data(ai->funcs->arg, session_number, data, 4); } -int en50221_app_ai_entermenu(en50221_app_ai ai, uint16_t session_number) +int en50221_app_ai_entermenu(struct en50221_app_ai *ai, + uint16_t session_number) { - struct en50221_app_ai_private *private = (struct en50221_app_ai_private *) ai; - uint8_t data[4]; + uint8_t data[4]; - data[0] = (TAG_ENTER_MENU >> 16) & 0xFF; - data[1] = (TAG_ENTER_MENU >> 8) & 0xFF; - data[2] = TAG_ENTER_MENU & 0xFF; - data[3] = 0; + data[0] = (TAG_ENTER_MENU >> 16) & 0xFF; + data[1] = (TAG_ENTER_MENU >> 8) & 0xFF; + data[2] = TAG_ENTER_MENU & 0xFF; + data[3] = 0; - return private->funcs->send_data(private->funcs->arg, session_number, data, 4); + return ai->funcs->send_data(ai->funcs->arg, session_number, data, 4); } -int en50221_app_ai_message(en50221_app_ai ai, - uint8_t slot_id, - uint16_t session_number, - uint32_t resource_id, - uint8_t *data, uint32_t data_length) +int en50221_app_ai_message(struct en50221_app_ai *ai, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t * data, uint32_t data_length) { - struct en50221_app_ai_private *private = (struct en50221_app_ai_private *) ai; - (void) resource_id; - - // get the tag - if (data_length < 3) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; - - switch(tag) - { - case TAG_APP_INFO: - return en50221_app_ai_parse_app_info(private, slot_id, session_number, data+3, data_length-3); - } - - print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); - return -1; + (void) resource_id; + + // get the tag + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; + + switch (tag) { + case TAG_APP_INFO: + return en50221_app_ai_parse_app_info(ai, slot_id, + session_number, + data + 3, + data_length - 3); + } + + print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); + return -1; } @@ -136,50 +137,55 @@ int en50221_app_ai_message(en50221_app_ai ai, -static int en50221_app_ai_parse_app_info(struct en50221_app_ai_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length) +static int en50221_app_ai_parse_app_info(struct en50221_app_ai *ai, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length) { - // parse the length field - int length_field_len; - uint16_t asn_data_length; - if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { - print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id); - return -1; - } - - // check it - if (asn_data_length < 6) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - if (asn_data_length > (data_length - length_field_len)) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - uint8_t *app_info = data + length_field_len; - - // parse the fields - uint8_t application_type = app_info[0]; - uint16_t application_manufacturer = (app_info[1] << 8) | app_info[2]; - uint16_t manufacturer_code = (app_info[3] << 8) | app_info[4]; - uint8_t menu_string_length = app_info[5]; - uint8_t *menu_string = app_info + 6; - - // check the menu_string_length - if (menu_string_length > (asn_data_length-6)) { - print(LOG_LEVEL, ERROR, 1, "Received bad menu string length - adjusting\n"); - menu_string_length = asn_data_length-6; - } - - // tell the app - pthread_mutex_lock(&private->lock); - en50221_app_ai_callback cb = private->callback; - void *cb_arg = private->callback_arg; - pthread_mutex_unlock(&private->lock); - if (cb) { - return cb(cb_arg, slot_id, session_number, application_type, - application_manufacturer, manufacturer_code, menu_string_length, menu_string); - } - return 0; + // parse the length field + int length_field_len; + uint16_t asn_data_length; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, + "Received data with invalid length from module on slot %02x\n", + slot_id); + return -1; + } + // check it + if (asn_data_length < 6) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (asn_data_length > (data_length - length_field_len)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint8_t *app_info = data + length_field_len; + + // parse the fields + uint8_t application_type = app_info[0]; + uint16_t application_manufacturer = (app_info[1] << 8) | app_info[2]; + uint16_t manufacturer_code = (app_info[3] << 8) | app_info[4]; + uint8_t menu_string_length = app_info[5]; + uint8_t *menu_string = app_info + 6; + + // check the menu_string_length + if (menu_string_length > (asn_data_length - 6)) { + print(LOG_LEVEL, ERROR, 1, + "Received bad menu string length - adjusting\n"); + menu_string_length = asn_data_length - 6; + } + // tell the app + pthread_mutex_lock(&ai->lock); + en50221_app_ai_callback cb = ai->callback; + void *cb_arg = ai->callback_arg; + pthread_mutex_unlock(&ai->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, + application_type, application_manufacturer, + manufacturer_code, menu_string_length, + menu_string); + } + return 0; } diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ai.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ai.h index 32d6e07..18b5cd2 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ai.h +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ai.h @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,15 +18,14 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __EN50221_APPLICATION_AI_H__ #define __EN50221_APPLICATION_AI_H__ #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif #include <stdlib.h> @@ -52,15 +51,19 @@ extern "C" * @param menu_string The menu string itself. * @return 0 on success, -1 on failure. */ -typedef int (*en50221_app_ai_callback)(void *arg, uint8_t slot_id, uint16_t session_number, - uint8_t application_type, uint16_t application_manufacturer, - uint16_t manufacturer_code, uint8_t menu_string_length, - uint8_t *menu_string); +typedef int (*en50221_app_ai_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number, + uint8_t application_type, + uint16_t application_manufacturer, + uint16_t manufacturer_code, + uint8_t menu_string_length, + uint8_t * menu_string); /** * Opaque type representing an application information resource. */ -typedef void *en50221_app_ai; +struct en50221_app_ai; /** * Create an instance of an application information resource. @@ -68,14 +71,14 @@ typedef void *en50221_app_ai; * @param funcs Send functions to use. * @return Instance, or NULL on failure. */ -extern en50221_app_ai en50221_app_ai_create(struct en50221_app_send_functions *funcs); +extern struct en50221_app_ai *en50221_app_ai_create(struct en50221_app_send_functions *funcs); /** * Destroy an instance of an application information resource. * * @param ai Instance to destroy. */ -extern void en50221_app_ai_destroy(en50221_app_ai ai); +extern void en50221_app_ai_destroy(struct en50221_app_ai *ai); /** * Register a callback for reception of application_info objects. @@ -84,7 +87,9 @@ extern void en50221_app_ai_destroy(en50221_app_ai ai); * @param callback Callback function. * @param arg Private argument passed during calls to the callback. */ -extern void en50221_app_ai_register_callback(en50221_app_ai ai, en50221_app_ai_callback, void *arg); +extern void en50221_app_ai_register_callback(struct en50221_app_ai *ai, + en50221_app_ai_callback, + void *arg); /** * send a enquiry for the app_info provided by a module @@ -93,7 +98,8 @@ extern void en50221_app_ai_register_callback(en50221_app_ai ai, en50221_app_ai_c * @param session_number Session to send on. * @return 0 on success, -1 on failure. */ -extern int en50221_app_ai_enquiry(en50221_app_ai ai, uint16_t session_number); +extern int en50221_app_ai_enquiry(struct en50221_app_ai *ai, + uint16_t session_number); /** * send a enter_menu tag, this will make the application @@ -103,7 +109,8 @@ extern int en50221_app_ai_enquiry(en50221_app_ai ai, uint16_t session_number); * @param session_number Session to send on. * @return 0 on success, -1 on failure. */ -extern int en50221_app_ai_entermenu(en50221_app_ai ai, uint16_t session_number); +extern int en50221_app_ai_entermenu(struct en50221_app_ai *ai, + uint16_t session_number); /** * Pass data received for this resource into it for parsing. @@ -116,14 +123,14 @@ extern int en50221_app_ai_entermenu(en50221_app_ai ai, uint16_t session_number); * @param data_length Length of data in bytes. * @return 0 on success, -1 on failure. */ -extern int en50221_app_ai_message(en50221_app_ai ai, - uint8_t slot_id, - uint16_t session_number, - uint32_t resource_id, - uint8_t *data, uint32_t data_length); +extern int en50221_app_ai_message(struct en50221_app_ai *ai, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, + uint32_t data_length); #ifdef __cplusplus } #endif - #endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_auth.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_auth.c index 8826c3b..a8902c1 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_auth.c +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_auth.c @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,7 +18,7 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <string.h> @@ -28,152 +28,153 @@ #include "en50221_app_tags.h" #include "asn_1.h" -struct en50221_app_auth_private { - struct en50221_app_send_functions *funcs; +struct en50221_app_auth { + struct en50221_app_send_functions *funcs; - en50221_app_auth_request_callback callback; - void *callback_arg; + en50221_app_auth_request_callback callback; + void *callback_arg; - pthread_mutex_t lock; + pthread_mutex_t lock; }; -static int en50221_app_auth_parse_request(struct en50221_app_auth_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length); +static int en50221_app_auth_parse_request(struct en50221_app_auth *private, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length); -en50221_app_auth en50221_app_auth_create(struct en50221_app_send_functions *funcs) +struct en50221_app_auth *en50221_app_auth_create(struct en50221_app_send_functions *funcs) { - struct en50221_app_auth_private *private = NULL; + struct en50221_app_auth *auth = NULL; - // create structure and set it up - private = malloc(sizeof(struct en50221_app_auth_private)); - if (private == NULL) { - return NULL; - } - private->funcs = funcs; - private->callback = NULL; + // create structure and set it up + auth = malloc(sizeof(struct en50221_app_auth)); + if (auth == NULL) { + return NULL; + } + auth->funcs = funcs; + auth->callback = NULL; - pthread_mutex_init(&private->lock, NULL); + pthread_mutex_init(&auth->lock, NULL); - // done - return private; + // done + return auth; } -void en50221_app_auth_destroy(en50221_app_auth auth) +void en50221_app_auth_destroy(struct en50221_app_auth *auth) { - struct en50221_app_auth_private *private = (struct en50221_app_auth_private *) auth; - - pthread_mutex_destroy(&private->lock); - free(private); + pthread_mutex_destroy(&auth->lock); + free(auth); } -void en50221_app_auth_register_request_callback(en50221_app_auth auth, - en50221_app_auth_request_callback callback, void *arg) +void en50221_app_auth_register_request_callback(struct en50221_app_auth *auth, + en50221_app_auth_request_callback callback, void *arg) { - struct en50221_app_auth_private *private = (struct en50221_app_auth_private *) auth; - - pthread_mutex_lock(&private->lock); - private->callback = callback; - private->callback_arg = arg; - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&auth->lock); + auth->callback = callback; + auth->callback_arg = arg; + pthread_mutex_unlock(&auth->lock); } -int en50221_app_auth_send(en50221_app_auth auth, - uint16_t session_number, - uint16_t auth_protocol_id, uint8_t *auth_data, - uint32_t auth_data_length) +int en50221_app_auth_send(struct en50221_app_auth *auth, + uint16_t session_number, + uint16_t auth_protocol_id, uint8_t * auth_data, + uint32_t auth_data_length) { - struct en50221_app_auth_private *private = (struct en50221_app_auth_private *) auth; - uint8_t buf[10]; - - // the header - buf[0] = (TAG_AUTH_RESP >> 16) & 0xFF; - buf[1] = (TAG_AUTH_RESP >> 8) & 0xFF; - buf[2] = TAG_AUTH_RESP & 0xFF; - - // encode the length field - int length_field_len; - if ((length_field_len = asn_1_encode(auth_data_length+2, buf+3, 3)) < 0) { - return -1; - } - - // the phase_id - buf[3+length_field_len] = auth_protocol_id>>8; - buf[3+length_field_len+1] = auth_protocol_id; - - // build the iovecs - struct iovec iov[2]; - iov[0].iov_base = buf; - iov[0].iov_len = 3+length_field_len+2; - iov[1].iov_base = auth_data; - iov[1].iov_len = auth_data_length; - - // sendit - return private->funcs->send_datav(private->funcs->arg, session_number, iov, 2); + uint8_t buf[10]; + + // the header + buf[0] = (TAG_AUTH_RESP >> 16) & 0xFF; + buf[1] = (TAG_AUTH_RESP >> 8) & 0xFF; + buf[2] = TAG_AUTH_RESP & 0xFF; + + // encode the length field + int length_field_len; + if ((length_field_len = asn_1_encode(auth_data_length + 2, buf + 3, 3)) < 0) { + return -1; + } + // the phase_id + buf[3 + length_field_len] = auth_protocol_id >> 8; + buf[3 + length_field_len + 1] = auth_protocol_id; + + // build the iovecs + struct iovec iov[2]; + iov[0].iov_base = buf; + iov[0].iov_len = 3 + length_field_len + 2; + iov[1].iov_base = auth_data; + iov[1].iov_len = auth_data_length; + + // sendit + return auth->funcs->send_datav(auth->funcs->arg, session_number, + iov, 2); } -int en50221_app_auth_message(en50221_app_auth auth, - uint8_t slot_id, - uint16_t session_number, - uint32_t resource_id, - uint8_t *data, uint32_t data_length) +int en50221_app_auth_message(struct en50221_app_auth *auth, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t * data, uint32_t data_length) { - struct en50221_app_auth_private *private = (struct en50221_app_auth_private *) auth; - (void) resource_id; - - // get the tag - if (data_length < 3) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; - - switch(tag) - { - case TAG_AUTH_REQ: - return en50221_app_auth_parse_request(private, slot_id, session_number, data+3, data_length-3); - } - - print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); - return -1; + (void) resource_id; + + // get the tag + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; + + switch (tag) { + case TAG_AUTH_REQ: + return en50221_app_auth_parse_request(auth, slot_id, + session_number, + data + 3, + data_length - 3); + } + + print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); + return -1; } -static int en50221_app_auth_parse_request(struct en50221_app_auth_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length) +static int en50221_app_auth_parse_request(struct en50221_app_auth *auth, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length) { - // first of all, decode the length field - uint16_t asn_data_length; - int length_field_len; - if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { - print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); - return -1; - } - - // check it - if (asn_data_length < 2) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - if (asn_data_length > (data_length-length_field_len)) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - uint8_t *auth_data = data + length_field_len; - - // process it - uint16_t auth_protocol_id = (auth_data[0]<<8) | auth_data[1]; - - // tell the app - pthread_mutex_lock(&private->lock); - en50221_app_auth_request_callback cb = private->callback; - void *cb_arg = private->callback_arg; - pthread_mutex_unlock(&private->lock); - if (cb) { - return cb(cb_arg, slot_id, session_number, auth_protocol_id, auth_data+2, asn_data_length-2); - } - return 0; + // first of all, decode the length field + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); + return -1; + } + // check it + if (asn_data_length < 2) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (asn_data_length > (data_length - length_field_len)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint8_t *auth_data = data + length_field_len; + + // process it + uint16_t auth_protocol_id = (auth_data[0] << 8) | auth_data[1]; + + // tell the app + pthread_mutex_lock(&auth->lock); + en50221_app_auth_request_callback cb = auth->callback; + void *cb_arg = auth->callback_arg; + pthread_mutex_unlock(&auth->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, + auth_protocol_id, auth_data + 2, + asn_data_length - 2); + } + return 0; } diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_auth.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_auth.h index c275089..2b1d2e7 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_auth.h +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_auth.h @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,15 +18,14 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __EN50221_APPLICATION_auth_H__ #define __EN50221_APPLICATION_auth_H__ #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif #include <stdlib.h> @@ -46,14 +45,17 @@ extern "C" * @param auth_data_lenghth Number of bytes. * @return 0 on success, -1 on failure. */ -typedef int (*en50221_app_auth_request_callback)(void *arg, uint8_t slot_id, uint16_t session_number, - uint16_t auth_protcol_id, uint8_t *auth_data, - uint32_t auth_data_length); +typedef int (*en50221_app_auth_request_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number, + uint16_t auth_protcol_id, + uint8_t *auth_data, + uint32_t auth_data_length); /** * Opaque type representing a auth resource. */ -typedef void *en50221_app_auth; +struct en50221_app_auth; /** * Create an instance of the auth resource. @@ -61,14 +63,14 @@ typedef void *en50221_app_auth; * @param funcs Send functions to use. * @return Instance, or NULL on failure. */ -extern en50221_app_auth en50221_app_auth_create(struct en50221_app_send_functions *funcs); +extern struct en50221_app_auth *en50221_app_auth_create(struct en50221_app_send_functions *funcs); /** * Destroy an instance of the auth resource. * * @param auth Instance to destroy. */ -extern void en50221_app_auth_destroy(en50221_app_auth auth); +extern void en50221_app_auth_destroy(struct en50221_app_auth *auth); /** * Register the callback for when we receive a request. @@ -77,8 +79,9 @@ extern void en50221_app_auth_destroy(en50221_app_auth auth); * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_app_auth_register_request_callback(en50221_app_auth auth, - en50221_app_auth_request_callback callback, void *arg); +extern void en50221_app_auth_register_request_callback(struct en50221_app_auth *auth, + en50221_app_auth_request_callback callback, + void *arg); /** * Send an auth response to the CAM. @@ -90,10 +93,11 @@ extern void en50221_app_auth_register_request_callback(en50221_app_auth auth, * @param auth_data_length Number of bytes. * @return 0 on success, -1 on failure. */ -extern int en50221_app_auth_send(en50221_app_auth auth, - uint16_t session_number, - uint16_t auth_protocol_id, uint8_t *auth_data, - uint32_t auth_data_length); +extern int en50221_app_auth_send(struct en50221_app_auth *auth, + uint16_t session_number, + uint16_t auth_protocol_id, + uint8_t *auth_data, + uint32_t auth_data_length); /** * Pass data received for this resource into it for parsing. @@ -106,14 +110,14 @@ extern int en50221_app_auth_send(en50221_app_auth auth, * @param data_length Length of data in bytes. * @return 0 on success, -1 on failure. */ -extern int en50221_app_auth_message(en50221_app_auth auth, - uint8_t slot_id, - uint16_t session_number, - uint32_t resource_id, - uint8_t *data, uint32_t data_length); +extern int en50221_app_auth_message(struct en50221_app_auth *auth, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, + uint32_t data_length); #ifdef __cplusplus } #endif - #endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ca.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ca.c index 0bdf74f..22d4499 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ca.c +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ca.c @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,7 +18,7 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <string.h> @@ -34,272 +34,277 @@ #define TAG_CA_PMT 0x9f8032 #define TAG_CA_PMT_REPLY 0x9f8033 -struct en50221_app_ca_private { - struct en50221_app_send_functions *funcs; +struct en50221_app_ca { + struct en50221_app_send_functions *funcs; - en50221_app_ca_info_callback ca_info_callback; - void *ca_info_callback_arg; + en50221_app_ca_info_callback ca_info_callback; + void *ca_info_callback_arg; - en50221_app_ca_pmt_reply_callback ca_pmt_reply_callback; - void *ca_pmt_reply_callback_arg; + en50221_app_ca_pmt_reply_callback ca_pmt_reply_callback; + void *ca_pmt_reply_callback_arg; - pthread_mutex_t lock; + pthread_mutex_t lock; }; struct ca_pmt_descriptor { - uint8_t *descriptor; - uint16_t length; + uint8_t *descriptor; + uint16_t length; - struct ca_pmt_descriptor *next; + struct ca_pmt_descriptor *next; }; struct ca_pmt_stream { - uint8_t stream_type; - uint16_t pid; - struct ca_pmt_descriptor *descriptors; - uint32_t descriptors_length; - uint32_t descriptors_count; + uint8_t stream_type; + uint16_t pid; + struct ca_pmt_descriptor *descriptors; + uint32_t descriptors_length; + uint32_t descriptors_count; - struct ca_pmt_stream *next; + struct ca_pmt_stream *next; }; -static int en50221_ca_extract_pmt_descriptors(struct mpeg_pmt_section *pmt, struct ca_pmt_descriptor **outdescriptors); -static int en50221_ca_extract_streams(struct mpeg_pmt_section *pmt, struct ca_pmt_stream **outstreams); +static int en50221_ca_extract_pmt_descriptors(struct mpeg_pmt_section *pmt, + struct ca_pmt_descriptor **outdescriptors); +static int en50221_ca_extract_streams(struct mpeg_pmt_section *pmt, + struct ca_pmt_stream **outstreams); static void en50221_ca_try_move_pmt_descriptors(struct ca_pmt_descriptor **pmt_descriptors, - struct ca_pmt_stream **pmt_streams); + struct ca_pmt_stream **pmt_streams); static uint32_t en50221_ca_calculate_length(struct ca_pmt_descriptor *pmt_descriptors, - uint32_t *pmt_descriptors_length, - struct ca_pmt_stream *pmt_streams); -static int en50221_app_ca_parse_info(struct en50221_app_ca_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length); -static int en50221_app_ca_parse_reply(struct en50221_app_ca_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length); + uint32_t *pmt_descriptors_length, + struct ca_pmt_stream *pmt_streams); +static int en50221_app_ca_parse_info(struct en50221_app_ca *ca, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, uint32_t data_length); +static int en50221_app_ca_parse_reply(struct en50221_app_ca *ca, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length); -en50221_app_ca en50221_app_ca_create(struct en50221_app_send_functions *funcs) +struct en50221_app_ca *en50221_app_ca_create(struct en50221_app_send_functions *funcs) { - struct en50221_app_ca_private *private = NULL; + struct en50221_app_ca *ca = NULL; - // create structure and set it up - private = malloc(sizeof(struct en50221_app_ca_private)); - if (private == NULL) { - return NULL; - } - private->funcs = funcs; - private->ca_info_callback = NULL; - private->ca_pmt_reply_callback = NULL; + // create structure and set it up + ca = malloc(sizeof(struct en50221_app_ca)); + if (ca == NULL) { + return NULL; + } + ca->funcs = funcs; + ca->ca_info_callback = NULL; + ca->ca_pmt_reply_callback = NULL; - pthread_mutex_init(&private->lock, NULL); + pthread_mutex_init(&ca->lock, NULL); - // done - return private; + // done + return ca; } -void en50221_app_ca_destroy(en50221_app_ca ca) +void en50221_app_ca_destroy(struct en50221_app_ca *ca) { - struct en50221_app_ca_private *private = (struct en50221_app_ca_private *) ca; - - pthread_mutex_destroy(&private->lock); - free(private); + pthread_mutex_destroy(&ca->lock); + free(ca); } -void en50221_app_ca_register_info_callback(en50221_app_ca ca, - en50221_app_ca_info_callback callback, void *arg) +void en50221_app_ca_register_info_callback(struct en50221_app_ca *ca, + en50221_app_ca_info_callback + callback, void *arg) { - struct en50221_app_ca_private *private = (struct en50221_app_ca_private *) ca; - - pthread_mutex_lock(&private->lock); - private->ca_info_callback = callback; - private->ca_info_callback_arg = arg; - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&ca->lock); + ca->ca_info_callback = callback; + ca->ca_info_callback_arg = arg; + pthread_mutex_unlock(&ca->lock); } -void en50221_app_ca_register_pmt_reply_callback(en50221_app_ca ca, - en50221_app_ca_pmt_reply_callback callback, void *arg) +void en50221_app_ca_register_pmt_reply_callback(struct en50221_app_ca *ca, + en50221_app_ca_pmt_reply_callback + callback, void *arg) { - struct en50221_app_ca_private *private = (struct en50221_app_ca_private *) ca; - - pthread_mutex_lock(&private->lock); - private->ca_pmt_reply_callback = callback; - private->ca_pmt_reply_callback_arg = arg; - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&ca->lock); + ca->ca_pmt_reply_callback = callback; + ca->ca_pmt_reply_callback_arg = arg; + pthread_mutex_unlock(&ca->lock); } -int en50221_app_ca_info_enq(en50221_app_ca ca, - uint16_t session_number) +int en50221_app_ca_info_enq(struct en50221_app_ca *ca, + uint16_t session_number) { - struct en50221_app_ca_private *private = (struct en50221_app_ca_private *) ca; - uint8_t data[4]; - - data[0] = (TAG_CA_INFO_ENQUIRY >> 16) & 0xFF; - data[1] = (TAG_CA_INFO_ENQUIRY >> 8) & 0xFF; - data[2] = TAG_CA_INFO_ENQUIRY & 0xFF; - data[3] = 0; - return private->funcs->send_data(private->funcs->arg, session_number, data, 4); + uint8_t data[4]; + + data[0] = (TAG_CA_INFO_ENQUIRY >> 16) & 0xFF; + data[1] = (TAG_CA_INFO_ENQUIRY >> 8) & 0xFF; + data[2] = TAG_CA_INFO_ENQUIRY & 0xFF; + data[3] = 0; + return ca->funcs->send_data(ca->funcs->arg, session_number, data, 4); } -int en50221_app_ca_pmt(en50221_app_ca ca, - uint16_t session_number, - uint8_t *ca_pmt, - uint32_t ca_pmt_length) +int en50221_app_ca_pmt(struct en50221_app_ca *ca, + uint16_t session_number, + uint8_t * ca_pmt, uint32_t ca_pmt_length) { - struct en50221_app_ca_private *private = (struct en50221_app_ca_private *) ca; - uint8_t buf[10]; - - // set up the tag - buf[0] = (TAG_CA_PMT >> 16) & 0xFF; - buf[1] = (TAG_CA_PMT >> 8) & 0xFF; - buf[2] = TAG_CA_PMT & 0xFF; - - // encode the length field - int length_field_len; - if ((length_field_len = asn_1_encode(ca_pmt_length, buf+3, 3)) < 0) { - return -1; - } - - // build the iovecs - struct iovec iov[2]; - iov[0].iov_base = buf; - iov[0].iov_len = 3+length_field_len; - iov[1].iov_base = ca_pmt; - iov[1].iov_len = ca_pmt_length; - - // create the data and send it - return private->funcs->send_datav(private->funcs->arg, session_number, iov, 2); + uint8_t buf[10]; + + // set up the tag + buf[0] = (TAG_CA_PMT >> 16) & 0xFF; + buf[1] = (TAG_CA_PMT >> 8) & 0xFF; + buf[2] = TAG_CA_PMT & 0xFF; + + // encode the length field + int length_field_len; + if ((length_field_len = asn_1_encode(ca_pmt_length, buf + 3, 3)) < 0) { + return -1; + } + // build the iovecs + struct iovec iov[2]; + iov[0].iov_base = buf; + iov[0].iov_len = 3 + length_field_len; + iov[1].iov_base = ca_pmt; + iov[1].iov_len = ca_pmt_length; + + // create the data and send it + return ca->funcs->send_datav(ca->funcs->arg, session_number, iov, 2); } -int en50221_app_ca_message(en50221_app_ca ca, - uint8_t slot_id, - uint16_t session_number, - uint32_t resource_id, - uint8_t *data, uint32_t data_length) +int en50221_app_ca_message(struct en50221_app_ca *ca, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t * data, uint32_t data_length) { - struct en50221_app_ca_private *private = (struct en50221_app_ca_private *) ca; - (void)resource_id; - - // get the tag - if (data_length < 3) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; - - switch(tag) - { - case TAG_CA_INFO: - return en50221_app_ca_parse_info(private, slot_id, session_number, data+3, data_length-3); - case TAG_CA_PMT_REPLY: - return en50221_app_ca_parse_reply(private, slot_id, session_number, data+3, data_length-3); - } - - print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); - return -1; + (void) resource_id; + + // get the tag + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; + + switch (tag) { + case TAG_CA_INFO: + return en50221_app_ca_parse_info(ca, slot_id, + session_number, data + 3, + data_length - 3); + case TAG_CA_PMT_REPLY: + return en50221_app_ca_parse_reply(ca, slot_id, + session_number, data + 3, + data_length - 3); + } + + print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); + return -1; } -int en50221_ca_format_pmt(struct mpeg_pmt_section *pmt, uint8_t *data, uint32_t data_length, - int move_ca_descriptors, - uint8_t ca_pmt_list_management, uint8_t ca_pmt_cmd_id) +int en50221_ca_format_pmt(struct mpeg_pmt_section *pmt, uint8_t * data, + uint32_t data_length, int move_ca_descriptors, + uint8_t ca_pmt_list_management, + uint8_t ca_pmt_cmd_id) { - struct ca_pmt_descriptor *pmt_descriptors = NULL; - uint32_t pmt_descriptors_length = 0; - struct ca_pmt_stream *pmt_streams = NULL; - uint32_t total_required_length = 0; - struct ca_pmt_descriptor *cur_d; - struct ca_pmt_stream *cur_s; - int result = -1; - - // extract the descriptors and streams - if (en50221_ca_extract_pmt_descriptors(pmt, &pmt_descriptors)) - goto cleanup; - if (en50221_ca_extract_streams(pmt, &pmt_streams)) - goto cleanup; - - // try and merge them if we have no PMT descriptors - if ((pmt_descriptors == NULL) && move_ca_descriptors) { - en50221_ca_try_move_pmt_descriptors(&pmt_descriptors, &pmt_streams); - } - - // calculate the length of all descriptors/streams and the total length required - total_required_length = en50221_ca_calculate_length(pmt_descriptors, &pmt_descriptors_length, pmt_streams); - - // ensure we were supplied with enough data - if (total_required_length > data_length) { - goto cleanup; - } - - // format the start of the PMT - uint32_t data_pos = 0; - data[data_pos++] = ca_pmt_list_management; - data[data_pos++] = mpeg_pmt_section_program_number(pmt) >> 8; - data[data_pos++] = mpeg_pmt_section_program_number(pmt); - data[data_pos++] = (pmt->head.version_number << 1) | pmt->head.current_next_indicator; - data[data_pos++] = (pmt_descriptors_length >> 8) & 0x0f; - data[data_pos++] = pmt_descriptors_length; - - // append the PMT descriptors - if (pmt_descriptors_length) { - data[data_pos++] = ca_pmt_cmd_id; - struct ca_pmt_descriptor *cur_d = pmt_descriptors; - while(cur_d) { - memcpy(data+data_pos, cur_d->descriptor, cur_d->length); - data_pos += cur_d->length; - cur_d = cur_d->next; - } - } - - // now, append the streams - cur_s = pmt_streams; - while(cur_s) { - data[data_pos++] = cur_s->stream_type; - data[data_pos++] = (cur_s->pid >> 8) & 0x1f; - data[data_pos++] = cur_s->pid; - data[data_pos++] = (cur_s->descriptors_length >> 8) & 0x0f; - data[data_pos++] = cur_s->descriptors_length; - - // append the stream descriptors - if (cur_s->descriptors_length) { - data[data_pos++] = ca_pmt_cmd_id; - struct ca_pmt_descriptor *cur_d = cur_s->descriptors; - while(cur_d) { - memcpy(data+data_pos, cur_d->descriptor, cur_d->length); - data_pos += cur_d->length; - cur_d = cur_d->next; - } - } - cur_s = cur_s->next; - } - result = data_pos; - - -cleanup: - // free the PMT descriptors - cur_d = pmt_descriptors; - while(cur_d) { - struct ca_pmt_descriptor *next = cur_d->next; - free(cur_d); - cur_d = next; - } - - // free the streams - cur_s = pmt_streams; - while(cur_s) { - struct ca_pmt_stream *next_s = cur_s->next; - - // free the stream descriptors - cur_d = cur_s->descriptors; - while(cur_d) { - struct ca_pmt_descriptor *next_d = cur_d->next; - free(cur_d); - cur_d = next_d; - } - - free(cur_s); - cur_s = next_s; - } - return result; + struct ca_pmt_descriptor *pmt_descriptors = NULL; + uint32_t pmt_descriptors_length = 0; + struct ca_pmt_stream *pmt_streams = NULL; + uint32_t total_required_length = 0; + struct ca_pmt_descriptor *cur_d; + struct ca_pmt_stream *cur_s; + int result = -1; + + // extract the descriptors and streams + if (en50221_ca_extract_pmt_descriptors(pmt, &pmt_descriptors)) + goto cleanup; + if (en50221_ca_extract_streams(pmt, &pmt_streams)) + goto cleanup; + + // try and merge them if we have no PMT descriptors + if ((pmt_descriptors == NULL) && move_ca_descriptors) { + en50221_ca_try_move_pmt_descriptors(&pmt_descriptors, + &pmt_streams); + } + // calculate the length of all descriptors/streams and the total length required + total_required_length = + en50221_ca_calculate_length(pmt_descriptors, + &pmt_descriptors_length, + pmt_streams); + + // ensure we were supplied with enough data + if (total_required_length > data_length) { + goto cleanup; + } + // format the start of the PMT + uint32_t data_pos = 0; + data[data_pos++] = ca_pmt_list_management; + data[data_pos++] = mpeg_pmt_section_program_number(pmt) >> 8; + data[data_pos++] = mpeg_pmt_section_program_number(pmt); + data[data_pos++] = + (pmt->head.version_number << 1) | pmt->head. + current_next_indicator; + data[data_pos++] = (pmt_descriptors_length >> 8) & 0x0f; + data[data_pos++] = pmt_descriptors_length; + + // append the PMT descriptors + if (pmt_descriptors_length) { + data[data_pos++] = ca_pmt_cmd_id; + cur_d = pmt_descriptors; + while (cur_d) { + memcpy(data + data_pos, cur_d->descriptor, + cur_d->length); + data_pos += cur_d->length; + cur_d = cur_d->next; + } + } + // now, append the streams + cur_s = pmt_streams; + while (cur_s) { + data[data_pos++] = cur_s->stream_type; + data[data_pos++] = (cur_s->pid >> 8) & 0x1f; + data[data_pos++] = cur_s->pid; + data[data_pos++] = (cur_s->descriptors_length >> 8) & 0x0f; + data[data_pos++] = cur_s->descriptors_length; + + // append the stream descriptors + if (cur_s->descriptors_length) { + data[data_pos++] = ca_pmt_cmd_id; + cur_d = cur_s->descriptors; + while (cur_d) { + memcpy(data + data_pos, cur_d->descriptor, + cur_d->length); + data_pos += cur_d->length; + cur_d = cur_d->next; + } + } + cur_s = cur_s->next; + } + result = data_pos; + + + cleanup: + // free the PMT descriptors + cur_d = pmt_descriptors; + while (cur_d) { + struct ca_pmt_descriptor *next = cur_d->next; + free(cur_d); + cur_d = next; + } + + // free the streams + cur_s = pmt_streams; + while (cur_s) { + struct ca_pmt_stream *next_s = cur_s->next; + + // free the stream descriptors + cur_d = cur_s->descriptors; + while (cur_d) { + struct ca_pmt_descriptor *next_d = cur_d->next; + free(cur_d); + cur_d = next_d; + } + + free(cur_s); + cur_s = next_s; + } + return result; } @@ -308,308 +313,319 @@ cleanup: -static int en50221_ca_extract_pmt_descriptors(struct mpeg_pmt_section *pmt, struct ca_pmt_descriptor **outdescriptors) +static int en50221_ca_extract_pmt_descriptors(struct mpeg_pmt_section *pmt, + struct ca_pmt_descriptor **outdescriptors) { - struct ca_pmt_descriptor *descriptors = NULL; - struct ca_pmt_descriptor *descriptors_tail = NULL; - struct ca_pmt_descriptor *cur_d; - - struct descriptor *cur_descriptor; - mpeg_pmt_section_descriptors_for_each(pmt, cur_descriptor) { - if (cur_descriptor->tag == dtag_mpeg_ca) { - // create a new structure for this one - struct ca_pmt_descriptor *new_d = malloc(sizeof(struct ca_pmt_descriptor)); - if (new_d == NULL) { - goto error_exit; - } - new_d->descriptor = (uint8_t*) cur_descriptor; - new_d->length = cur_descriptor->len+2; - new_d->next = NULL; - - // append it to the list - if (descriptors == NULL) { - descriptors = new_d; - } else { - descriptors_tail->next = new_d; - } - descriptors_tail = new_d; - } - } - *outdescriptors = descriptors; - return 0; + struct ca_pmt_descriptor *descriptors = NULL; + struct ca_pmt_descriptor *descriptors_tail = NULL; + struct ca_pmt_descriptor *cur_d; + + struct descriptor *cur_descriptor; + mpeg_pmt_section_descriptors_for_each(pmt, cur_descriptor) { + if (cur_descriptor->tag == dtag_mpeg_ca) { + // create a new structure for this one + struct ca_pmt_descriptor *new_d = + malloc(sizeof(struct ca_pmt_descriptor)); + if (new_d == NULL) { + goto error_exit; + } + new_d->descriptor = (uint8_t *) cur_descriptor; + new_d->length = cur_descriptor->len + 2; + new_d->next = NULL; + + // append it to the list + if (descriptors == NULL) { + descriptors = new_d; + } else { + descriptors_tail->next = new_d; + } + descriptors_tail = new_d; + } + } + *outdescriptors = descriptors; + return 0; error_exit: - cur_d = descriptors; - while(cur_d) { - struct ca_pmt_descriptor *next = cur_d->next; - free(cur_d); - cur_d = next; - } - return -1; + cur_d = descriptors; + while (cur_d) { + struct ca_pmt_descriptor *next = cur_d->next; + free(cur_d); + cur_d = next; + } + return -1; } -static int en50221_ca_extract_streams(struct mpeg_pmt_section *pmt, struct ca_pmt_stream **outstreams) +static int en50221_ca_extract_streams(struct mpeg_pmt_section *pmt, + struct ca_pmt_stream **outstreams) { - struct ca_pmt_stream *streams = NULL; - struct ca_pmt_stream *streams_tail = NULL; - struct mpeg_pmt_stream *cur_stream; - struct descriptor *cur_descriptor; - struct ca_pmt_stream *cur_s; - - mpeg_pmt_section_streams_for_each(pmt, cur_stream) { - struct ca_pmt_descriptor *descriptors_tail = NULL; - - // create a new structure - struct ca_pmt_stream *new_s = malloc(sizeof(struct ca_pmt_stream)); - if (new_s == NULL) { - goto exit_cleanup; - } - new_s->stream_type = cur_stream->stream_type; - new_s->pid = cur_stream->pid; - new_s->descriptors = NULL; - new_s->next = NULL; - new_s->descriptors_count = 0; - - // append it to the list - if (streams == NULL) { - streams = new_s; - } else { - streams_tail->next = new_s; - } - streams_tail = new_s; - - // now process the descriptors - mpeg_pmt_stream_descriptors_for_each(cur_stream, cur_descriptor) { - if (cur_descriptor->tag == dtag_mpeg_ca) { - // create a new structure - struct ca_pmt_descriptor *new_d = malloc(sizeof(struct ca_pmt_descriptor)); - if (new_d == NULL) { - goto exit_cleanup; - } - new_d->descriptor = (uint8_t*) cur_descriptor; - new_d->length = cur_descriptor->len+2; - new_d->next = NULL; - - // append it to the list - if (new_s->descriptors == NULL) { - new_s->descriptors = new_d; - } else { - descriptors_tail->next = new_d; - } - descriptors_tail = new_d; - new_s->descriptors_count++; - } - } - } - *outstreams = streams; - return 0; + struct ca_pmt_stream *streams = NULL; + struct ca_pmt_stream *streams_tail = NULL; + struct mpeg_pmt_stream *cur_stream; + struct descriptor *cur_descriptor; + struct ca_pmt_stream *cur_s; + + mpeg_pmt_section_streams_for_each(pmt, cur_stream) { + struct ca_pmt_descriptor *descriptors_tail = NULL; + + // create a new structure + struct ca_pmt_stream *new_s = + malloc(sizeof(struct ca_pmt_stream)); + if (new_s == NULL) { + goto exit_cleanup; + } + new_s->stream_type = cur_stream->stream_type; + new_s->pid = cur_stream->pid; + new_s->descriptors = NULL; + new_s->next = NULL; + new_s->descriptors_count = 0; + + // append it to the list + if (streams == NULL) { + streams = new_s; + } else { + streams_tail->next = new_s; + } + streams_tail = new_s; + + // now process the descriptors + mpeg_pmt_stream_descriptors_for_each(cur_stream, + cur_descriptor) { + if (cur_descriptor->tag == dtag_mpeg_ca) { + // create a new structure + struct ca_pmt_descriptor *new_d = + malloc(sizeof(struct ca_pmt_descriptor)); + if (new_d == NULL) { + goto exit_cleanup; + } + new_d->descriptor = + (uint8_t *) cur_descriptor; + new_d->length = cur_descriptor->len + 2; + new_d->next = NULL; + + // append it to the list + if (new_s->descriptors == NULL) { + new_s->descriptors = new_d; + } else { + descriptors_tail->next = new_d; + } + descriptors_tail = new_d; + new_s->descriptors_count++; + } + } + } + *outstreams = streams; + return 0; exit_cleanup: - // free the streams - cur_s = streams; - while(cur_s) { - struct ca_pmt_stream *next_s = cur_s->next; - - // free the stream descriptors - struct ca_pmt_descriptor *cur_d = cur_s->descriptors; - while(cur_d) { - struct ca_pmt_descriptor *next_d = cur_d->next; - free(cur_d); - cur_d = next_d; - } - - free(cur_s); - cur_s = next_s; - } - return -1; + // free the streams + cur_s = streams; + while (cur_s) { + struct ca_pmt_stream *next_s = cur_s->next; + + // free the stream descriptors + struct ca_pmt_descriptor *cur_d = cur_s->descriptors; + while (cur_d) { + struct ca_pmt_descriptor *next_d = cur_d->next; + free(cur_d); + cur_d = next_d; + } + + free(cur_s); + cur_s = next_s; + } + return -1; } static void en50221_ca_try_move_pmt_descriptors(struct ca_pmt_descriptor **pmt_descriptors, - struct ca_pmt_stream **pmt_streams) + struct ca_pmt_stream **pmt_streams) { - // get the first stream - struct ca_pmt_stream *first_stream = *pmt_streams; - if (first_stream == NULL) - return; - - // Check that all the other streams with CA descriptors have exactly the same CA descriptors - struct ca_pmt_stream *cur_stream = first_stream->next; - while(cur_stream) { - // if there are differing numbers of descriptors, exit right now - if (cur_stream->descriptors_count != first_stream->descriptors_count) - return; - - // now verify the descriptors match - struct ca_pmt_descriptor *cur_descriptor = cur_stream->descriptors; - struct ca_pmt_descriptor *first_cur_descriptor = first_stream->descriptors; - while(cur_descriptor) { - // check the descriptors are the same length - if (cur_descriptor->length != first_cur_descriptor->length) - return; - - // check their contents match - if (memcmp(cur_descriptor->descriptor, first_cur_descriptor->descriptor, cur_descriptor->length)) { - return; - } - - // move to next - cur_descriptor = cur_descriptor->next; - first_cur_descriptor = first_cur_descriptor->next; - } - - // move to next - cur_stream = cur_stream->next; - } - - // if we end up here, all descriptors in all streams matched - - // hook the first stream's descriptors into the PMT's - *pmt_descriptors = first_stream->descriptors; - first_stream->descriptors = NULL; - first_stream->descriptors_count = 0; - - // now free up all the descriptors in the other streams - cur_stream = first_stream->next; - while(cur_stream) { - struct ca_pmt_descriptor *cur_descriptor = cur_stream->descriptors; - while(cur_descriptor) { - struct ca_pmt_descriptor *next = cur_descriptor->next; - free(cur_descriptor); - cur_descriptor=next; - } - cur_stream->descriptors = NULL; - cur_stream->descriptors_count = 0; - cur_stream = cur_stream->next; - } + // get the first stream + struct ca_pmt_stream *first_stream = *pmt_streams; + if (first_stream == NULL) + return; + + // Check that all the other streams with CA descriptors have exactly the same CA descriptors + struct ca_pmt_stream *cur_stream = first_stream->next; + while (cur_stream) { + // if there are differing numbers of descriptors, exit right now + if (cur_stream->descriptors_count != first_stream->descriptors_count) + return; + + // now verify the descriptors match + struct ca_pmt_descriptor *cur_descriptor = cur_stream->descriptors; + struct ca_pmt_descriptor *first_cur_descriptor = first_stream->descriptors; + while (cur_descriptor) { + // check the descriptors are the same length + if (cur_descriptor->length != first_cur_descriptor->length) + return; + + // check their contents match + if (memcmp(cur_descriptor->descriptor, + first_cur_descriptor->descriptor, + cur_descriptor->length)) { + return; + } + // move to next + cur_descriptor = cur_descriptor->next; + first_cur_descriptor = first_cur_descriptor->next; + } + + // move to next + cur_stream = cur_stream->next; + } + + // if we end up here, all descriptors in all streams matched + + // hook the first stream's descriptors into the PMT's + *pmt_descriptors = first_stream->descriptors; + first_stream->descriptors = NULL; + first_stream->descriptors_count = 0; + + // now free up all the descriptors in the other streams + cur_stream = first_stream->next; + while (cur_stream) { + struct ca_pmt_descriptor *cur_descriptor = cur_stream->descriptors; + while (cur_descriptor) { + struct ca_pmt_descriptor *next = cur_descriptor->next; + free(cur_descriptor); + cur_descriptor = next; + } + cur_stream->descriptors = NULL; + cur_stream->descriptors_count = 0; + cur_stream = cur_stream->next; + } } static uint32_t en50221_ca_calculate_length(struct ca_pmt_descriptor *pmt_descriptors, - uint32_t *pmt_descriptors_length, - struct ca_pmt_stream *pmt_streams) + uint32_t *pmt_descriptors_length, + struct ca_pmt_stream *pmt_streams) { - uint32_t total_required_length = 6; // header - struct ca_pmt_stream *cur_s; - - // calcuate the PMT descriptors length - (*pmt_descriptors_length) = 0; - struct ca_pmt_descriptor *cur_d = pmt_descriptors; - while(cur_d) { - (*pmt_descriptors_length) += cur_d->length; - cur_d = cur_d->next; - } - - // add on 1 byte for the ca_pmt_cmd_id if we have some descriptors. - if (*pmt_descriptors_length) - (*pmt_descriptors_length)++; - - // update the total required length - total_required_length += *pmt_descriptors_length; - - // calculate the length of descriptors in the streams - cur_s = pmt_streams; - while(cur_s) { - // calculate the size of descriptors in this stream - cur_s->descriptors_length = 0; - cur_d = cur_s->descriptors; - while(cur_d) { - cur_s->descriptors_length += cur_d->length; - cur_d = cur_d->next; - } - - // add on 1 byte for the ca_pmt_cmd_id if we have some descriptors. - if (cur_s->descriptors_length) - cur_s->descriptors_length++; - - // update the total required length; - total_required_length += 5 + cur_s->descriptors_length; - - cur_s = cur_s->next; - } - - // done - return total_required_length; + uint32_t total_required_length = 6; // header + struct ca_pmt_stream *cur_s; + + // calcuate the PMT descriptors length + (*pmt_descriptors_length) = 0; + struct ca_pmt_descriptor *cur_d = pmt_descriptors; + while (cur_d) { + (*pmt_descriptors_length) += cur_d->length; + cur_d = cur_d->next; + } + + // add on 1 byte for the ca_pmt_cmd_id if we have some descriptors. + if (*pmt_descriptors_length) + (*pmt_descriptors_length)++; + + // update the total required length + total_required_length += *pmt_descriptors_length; + + // calculate the length of descriptors in the streams + cur_s = pmt_streams; + while (cur_s) { + // calculate the size of descriptors in this stream + cur_s->descriptors_length = 0; + cur_d = cur_s->descriptors; + while (cur_d) { + cur_s->descriptors_length += cur_d->length; + cur_d = cur_d->next; + } + + // add on 1 byte for the ca_pmt_cmd_id if we have some descriptors. + if (cur_s->descriptors_length) + cur_s->descriptors_length++; + + // update the total required length; + total_required_length += 5 + cur_s->descriptors_length; + + cur_s = cur_s->next; + } + + // done + return total_required_length; } -static int en50221_app_ca_parse_info(struct en50221_app_ca_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length) +static int en50221_app_ca_parse_info(struct en50221_app_ca *ca, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, uint32_t data_length) { - // first of all, decode the length field - uint16_t asn_data_length; - int length_field_len; - if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { - print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); - return -1; - } - - // check it - if (asn_data_length > (data_length-length_field_len)) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - data+=length_field_len; - - // parse - uint32_t ca_id_count = asn_data_length / 2; - - // byteswap the IDs - uint16_t *ids = (uint16_t*) data; - uint32_t i; - for(i=0; i<ca_id_count; i++) { - bswap16(data); - data+=2; - } - - // tell the app - pthread_mutex_lock(&private->lock); - en50221_app_ca_info_callback cb = private->ca_info_callback; - void *cb_arg = private->ca_info_callback_arg; - pthread_mutex_unlock(&private->lock); - if (cb) { - return cb(cb_arg, slot_id, session_number, ca_id_count, ids); - } - return 0; + // first of all, decode the length field + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); + return -1; + } + // check it + if (asn_data_length > (data_length - length_field_len)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + data += length_field_len; + + // parse + uint32_t ca_id_count = asn_data_length / 2; + + // byteswap the IDs + uint16_t *ids = (uint16_t *) data; + uint32_t i; + for (i = 0; i < ca_id_count; i++) { + bswap16(data); + data += 2; + } + + // tell the app + pthread_mutex_lock(&ca->lock); + en50221_app_ca_info_callback cb = ca->ca_info_callback; + void *cb_arg = ca->ca_info_callback_arg; + pthread_mutex_unlock(&ca->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, ca_id_count, + ids); + } + return 0; } -static int en50221_app_ca_parse_reply(struct en50221_app_ca_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length) +static int en50221_app_ca_parse_reply(struct en50221_app_ca *ca, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, uint32_t data_length) { - // first of all, decode the length field - uint16_t asn_data_length; - int length_field_len; - if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { - print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); - return -1; - } - - // check it - if (asn_data_length < 4) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - if (asn_data_length > (data_length-length_field_len)) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - data += length_field_len; - data_length -= length_field_len; - - // process the reply table to fix endian issues - uint32_t pos = 4; - bswap16(data); - while(pos < asn_data_length) { - bswap16(data+pos); - pos+= 3; - } - - // tell the app - pthread_mutex_lock(&private->lock); - en50221_app_ca_pmt_reply_callback cb = private->ca_pmt_reply_callback; - void *cb_arg = private->ca_pmt_reply_callback_arg; - pthread_mutex_unlock(&private->lock); - if (cb) { - return cb(cb_arg, slot_id, session_number, (struct en50221_app_pmt_reply*) data, asn_data_length); - } - return 0; + // first of all, decode the length field + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); + return -1; + } + // check it + if (asn_data_length < 4) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (asn_data_length > (data_length - length_field_len)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + data += length_field_len; + data_length -= length_field_len; + + // process the reply table to fix endian issues + uint32_t pos = 4; + bswap16(data); + while (pos < asn_data_length) { + bswap16(data + pos); + pos += 3; + } + + // tell the app + pthread_mutex_lock(&ca->lock); + en50221_app_ca_pmt_reply_callback cb = ca->ca_pmt_reply_callback; + void *cb_arg = ca->ca_pmt_reply_callback_arg; + pthread_mutex_unlock(&ca->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, + (struct en50221_app_pmt_reply *) data, + asn_data_length); + } + return 0; } diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ca.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ca.h index 846312b..7405b06 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ca.h +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ca.h @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,15 +18,14 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __EN50221_APPLICATION_ca_H__ #define __EN50221_APPLICATION_ca_H__ #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif #include <stdlib.h> @@ -60,24 +59,24 @@ extern "C" * PMT reply structure. */ struct en50221_app_pmt_reply { - uint16_t program_number; - EBIT3(uint8_t reserved_1 : 2; , - uint8_t version_number : 5; , - uint8_t current_next_indicator : 1; ) - EBIT2(uint8_t CA_enable_flag : 1; , - uint8_t CA_enable : 7; ) - /* struct en50221_app_pmt_stream streams[] */ -} __attribute__((packed)); + uint16_t program_number; + EBIT3(uint8_t reserved_1 : 2;, + uint8_t version_number : 5;, + uint8_t current_next_indicator : 1;); + EBIT2(uint8_t CA_enable_flag : 1;, + uint8_t CA_enable : 7;); + /* struct en50221_app_pmt_stream streams[] */ +} __attribute__ ((packed)); /** * A stream within a pmt reply structure. */ struct en50221_app_pmt_stream { - EBIT2(uint16_t reserved_1 : 3; , - uint16_t es_pid :13; ) - EBIT2(uint8_t CA_enable_flag : 1; , - uint8_t CA_enable : 7; ) -} __attribute__((packed)); + EBIT2(uint16_t reserved_1 : 3;, + uint16_t es_pid :13;); + EBIT2(uint8_t CA_enable_flag : 1;, + uint8_t CA_enable : 7;); +} __attribute__ ((packed)); /** * Convenience iterator for the streams field of the en50221_app_pmt_reply structure. @@ -102,9 +101,11 @@ struct en50221_app_pmt_stream { * @param ca_ids Pointer to list of ca_system_ids. * @return 0 on success, -1 on failure. */ -typedef int (*en50221_app_ca_info_callback)(void *arg, uint8_t slot_id, uint16_t session_number, - uint32_t ca_id_count, - uint16_t *ca_ids); +typedef int (*en50221_app_ca_info_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number, + uint32_t ca_id_count, + uint16_t * ca_ids); /** * Type definition for pmt_reply - called when we receive a pmt_reply. @@ -116,14 +117,16 @@ typedef int (*en50221_app_ca_info_callback)(void *arg, uint8_t slot_id, uint16_t * @param reply_size Total size of the struct en50221_app_pmt_reply in bytes. * @return 0 on success, -1 on failure. */ -typedef int (*en50221_app_ca_pmt_reply_callback)(void *arg, uint8_t slot_id, uint16_t session_number, - struct en50221_app_pmt_reply *reply, - uint32_t reply_size); +typedef int (*en50221_app_ca_pmt_reply_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number, + struct en50221_app_pmt_reply *reply, + uint32_t reply_size); /** * Opaque type representing a ca resource. */ -typedef void *en50221_app_ca; +struct en50221_app_ca; /** * Create an instance of the ca resource. @@ -131,14 +134,14 @@ typedef void *en50221_app_ca; * @param funcs Send functions to use. * @return Instance, or NULL on failure. */ -extern en50221_app_ca en50221_app_ca_create(struct en50221_app_send_functions *funcs); +extern struct en50221_app_ca *en50221_app_ca_create(struct en50221_app_send_functions *funcs); /** * Destroy an instance of the ca resource. * * @param ca Instance to destroy. */ -extern void en50221_app_ca_destroy(en50221_app_ca ca); +extern void en50221_app_ca_destroy(struct en50221_app_ca *ca); /** * Register the callback for when we receive a ca info. @@ -147,8 +150,9 @@ extern void en50221_app_ca_destroy(en50221_app_ca ca); * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_app_ca_register_info_callback(en50221_app_ca ca, - en50221_app_ca_info_callback callback, void *arg); +extern void en50221_app_ca_register_info_callback(struct en50221_app_ca *ca, + en50221_app_ca_info_callback callback, + void *arg); /** * Register the callback for when we receive a pmt_reply. @@ -157,8 +161,9 @@ extern void en50221_app_ca_register_info_callback(en50221_app_ca ca, * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_app_ca_register_pmt_reply_callback(en50221_app_ca ca, - en50221_app_ca_pmt_reply_callback callback, void *arg); +extern void en50221_app_ca_register_pmt_reply_callback(struct en50221_app_ca *ca, + en50221_app_ca_pmt_reply_callback callback, + void *arg); /** * Send a ca_info_req to the CAM. @@ -167,8 +172,8 @@ extern void en50221_app_ca_register_pmt_reply_callback(en50221_app_ca ca, * @param session_number Session number to send it on. * @return 0 on success, -1 on failure. */ -extern int en50221_app_ca_info_enq(en50221_app_ca ca, - uint16_t session_number); +extern int en50221_app_ca_info_enq(struct en50221_app_ca *ca, + uint16_t session_number); /** * Send a ca_pmt structure to the CAM. @@ -179,10 +184,10 @@ extern int en50221_app_ca_info_enq(en50221_app_ca ca, * @param ca_pmt_length Length of ca_pmt structure in bytes. * @return 0 on success, -1 on failure. */ -extern int en50221_app_ca_pmt(en50221_app_ca ca, - uint16_t session_number, - uint8_t *ca_pmt, - uint32_t ca_pmt_length); +extern int en50221_app_ca_pmt(struct en50221_app_ca *ca, + uint16_t session_number, + uint8_t * ca_pmt, + uint32_t ca_pmt_length); /** * Transform a libucsi PMT into a binary structure for sending to a CAM. @@ -197,10 +202,11 @@ extern int en50221_app_ca_pmt(en50221_app_ca ca, * @return Number of bytes used, or -1 on error. */ extern int en50221_ca_format_pmt(struct mpeg_pmt_section *pmt, - uint8_t *data, - uint32_t data_length, - int move_ca_descriptors, - uint8_t ca_pmt_list_management, uint8_t ca_pmt_cmd_id); + uint8_t * data, + uint32_t data_length, + int move_ca_descriptors, + uint8_t ca_pmt_list_management, + uint8_t ca_pmt_cmd_id); /** * Pass data received for this resource into it for parsing. @@ -213,38 +219,42 @@ extern int en50221_ca_format_pmt(struct mpeg_pmt_section *pmt, * @param data_length Length of data in bytes. * @return 0 on success, -1 on failure. */ -extern int en50221_app_ca_message(en50221_app_ca ca, - uint8_t slot_id, - uint16_t session_number, - uint32_t resource_id, - uint8_t *data, uint32_t data_length); +extern int en50221_app_ca_message(struct en50221_app_ca *ca, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, + uint32_t data_length); static inline struct en50221_app_pmt_stream * - en50221_app_pmt_reply_streams_first(struct en50221_app_pmt_reply *reply, uint32_t reply_size) + en50221_app_pmt_reply_streams_first(struct en50221_app_pmt_reply *reply, + uint32_t reply_size) { - uint32_t pos = sizeof(struct en50221_app_pmt_reply); + uint32_t pos = sizeof(struct en50221_app_pmt_reply); - if (pos >= reply_size) - return NULL; + if (pos >= reply_size) + return NULL; - return (struct en50221_app_pmt_stream *)((uint8_t *)reply+ pos); + return (struct en50221_app_pmt_stream *) ((uint8_t *) reply + pos); } static inline struct en50221_app_pmt_stream * - en50221_app_pmt_reply_streams_next(struct en50221_app_pmt_reply * reply, - struct en50221_app_pmt_stream * pos, - uint32_t reply_size) + en50221_app_pmt_reply_streams_next(struct en50221_app_pmt_reply *reply, + struct en50221_app_pmt_stream *pos, + uint32_t reply_size) { - uint8_t *end = (uint8_t*) reply + reply_size; - uint8_t *next = (uint8_t *) pos + sizeof(struct en50221_app_pmt_stream); + uint8_t *end = (uint8_t *) reply + reply_size; + uint8_t *next = + (uint8_t *) pos + + sizeof(struct en50221_app_pmt_stream); - if (next >= end) - return NULL; + if (next >= end) + return NULL; - return (struct en50221_app_pmt_stream *) next; + return (struct en50221_app_pmt_stream *) next; } #ifdef __cplusplus diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_datetime.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_datetime.c index e21304c..6777003 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_datetime.c +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_datetime.c @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,7 +18,7 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <string.h> @@ -29,108 +29,109 @@ #include "en50221_app_tags.h" #include "asn_1.h" -struct en50221_app_datetime_private { - struct en50221_app_send_functions *funcs; +struct en50221_app_datetime { + struct en50221_app_send_functions *funcs; - en50221_app_datetime_enquiry_callback callback; - void *callback_arg; + en50221_app_datetime_enquiry_callback callback; + void *callback_arg; - pthread_mutex_t lock; + pthread_mutex_t lock; }; -static int en50221_app_datetime_parse_enquiry(struct en50221_app_datetime_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length); +static int en50221_app_datetime_parse_enquiry(struct en50221_app_datetime *datetime, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length); -en50221_app_datetime en50221_app_datetime_create(struct en50221_app_send_functions *funcs) +struct en50221_app_datetime *en50221_app_datetime_create(struct en50221_app_send_functions *funcs) { - struct en50221_app_datetime_private *private = NULL; + struct en50221_app_datetime *datetime = NULL; - // create structure and set it up - private = malloc(sizeof(struct en50221_app_datetime_private)); - if (private == NULL) { - return NULL; - } - private->funcs = funcs; - private->callback = NULL; + // create structure and set it up + datetime = malloc(sizeof(struct en50221_app_datetime)); + if (datetime == NULL) { + return NULL; + } + datetime->funcs = funcs; + datetime->callback = NULL; - pthread_mutex_init(&private->lock, NULL); + pthread_mutex_init(&datetime->lock, NULL); - // done - return private; + // done + return datetime; } -void en50221_app_datetime_destroy(en50221_app_datetime datetime) +void en50221_app_datetime_destroy(struct en50221_app_datetime *datetime) { - struct en50221_app_datetime_private *private = (struct en50221_app_datetime_private *) datetime; - - pthread_mutex_destroy(&private->lock); - free(private); + pthread_mutex_destroy(&datetime->lock); + free(datetime); } -void en50221_app_datetime_register_enquiry_callback(en50221_app_datetime datetime, - en50221_app_datetime_enquiry_callback callback, void *arg) +void en50221_app_datetime_register_enquiry_callback(struct en50221_app_datetime *datetime, + en50221_app_datetime_enquiry_callback callback, + void *arg) { - struct en50221_app_datetime_private *private = (struct en50221_app_datetime_private *) datetime; - - pthread_mutex_lock(&private->lock); - private->callback = callback; - private->callback_arg = arg; - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&datetime->lock); + datetime->callback = callback; + datetime->callback_arg = arg; + pthread_mutex_unlock(&datetime->lock); } -int en50221_app_datetime_send(en50221_app_datetime datetime, - uint16_t session_number, - time_t utc_time, - int time_offset) +int en50221_app_datetime_send(struct en50221_app_datetime *datetime, + uint16_t session_number, + time_t utc_time, int time_offset) { - struct en50221_app_datetime_private *private = (struct en50221_app_datetime_private *) datetime; - uint8_t data[11]; - int data_length; - - data[0] = (TAG_DATE_TIME >> 16) & 0xFF; - data[1] = (TAG_DATE_TIME >> 8) & 0xFF; - data[2] = TAG_DATE_TIME & 0xFF; - if (time_offset != -1) { - data[3] = 7; - unixtime_to_dvbdate(utc_time, data+4); - data[9] = time_offset >> 8; - data[10] = time_offset; - data_length = 11; - } else { - data[3] = 5; - unixtime_to_dvbdate(utc_time, data+4); - data_length = 9; - } - return private->funcs->send_data(private->funcs->arg, session_number, data, data_length); + uint8_t data[11]; + int data_length; + + data[0] = (TAG_DATE_TIME >> 16) & 0xFF; + data[1] = (TAG_DATE_TIME >> 8) & 0xFF; + data[2] = TAG_DATE_TIME & 0xFF; + if (time_offset != -1) { + data[3] = 7; + unixtime_to_dvbdate(utc_time, data + 4); + data[9] = time_offset >> 8; + data[10] = time_offset; + data_length = 11; + } else { + data[3] = 5; + unixtime_to_dvbdate(utc_time, data + 4); + data_length = 9; + } + return datetime->funcs->send_data(datetime->funcs->arg, + session_number, data, + data_length); } -int en50221_app_datetime_message(en50221_app_datetime datetime, - uint8_t slot_id, - uint16_t session_number, - uint32_t resource_id, - uint8_t *data, uint32_t data_length) +int en50221_app_datetime_message(struct en50221_app_datetime *datetime, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t * data, uint32_t data_length) { - struct en50221_app_datetime_private *private = (struct en50221_app_datetime_private *) datetime; - (void) resource_id; - - // get the tag - if (data_length < 3) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; - - switch(tag) - { - case TAG_DATE_TIME_ENQUIRY: - return en50221_app_datetime_parse_enquiry(private, slot_id, session_number, data+3, data_length-3); - } - - print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); - return -1; + (void) resource_id; + + // get the tag + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; + + switch (tag) { + case TAG_DATE_TIME_ENQUIRY: + return en50221_app_datetime_parse_enquiry(datetime, + slot_id, + session_number, + data + 3, + data_length - 3); + } + + print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); + return -1; } @@ -142,28 +143,31 @@ int en50221_app_datetime_message(en50221_app_datetime datetime, -static int en50221_app_datetime_parse_enquiry(struct en50221_app_datetime_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length) +static int en50221_app_datetime_parse_enquiry(struct en50221_app_datetime *datetime, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length) { - // validate data - if (data_length != 2) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - if (data[0] != 1) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - uint8_t response_interval = data[1]; - - // tell the app - pthread_mutex_lock(&private->lock); - en50221_app_datetime_enquiry_callback cb = private->callback; - void *cb_arg = private->callback_arg; - pthread_mutex_unlock(&private->lock); - if (cb) { - return cb(cb_arg, slot_id, session_number, response_interval); - } - return 0; + // validate data + if (data_length != 2) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (data[0] != 1) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint8_t response_interval = data[1]; + + // tell the app + pthread_mutex_lock(&datetime->lock); + en50221_app_datetime_enquiry_callback cb = datetime->callback; + void *cb_arg = datetime->callback_arg; + pthread_mutex_unlock(&datetime->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, + response_interval); + } + return 0; } diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_datetime.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_datetime.h index df813e1..4660630 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_datetime.h +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_datetime.h @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,15 +18,14 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __EN50221_APPLICATION_DATETIME_H__ #define __EN50221_APPLICATION_DATETIME_H__ #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif #include <stdlib.h> @@ -44,13 +43,15 @@ extern "C" * @param response_interval Response interval requested by CAM. * @return 0 on success, -1 on failure. */ -typedef int (*en50221_app_datetime_enquiry_callback)(void *arg, uint8_t slot_id, uint16_t session_number, - uint8_t response_interval); +typedef int (*en50221_app_datetime_enquiry_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number, + uint8_t response_interval); /** * Opaque type representing a datetime resource. */ -typedef void *en50221_app_datetime; +struct en50221_app_datetime; /** * Create an instance of the datetime resource. @@ -58,14 +59,15 @@ typedef void *en50221_app_datetime; * @param funcs Send functions to use. * @return Instance, or NULL on failure. */ -extern en50221_app_datetime en50221_app_datetime_create(struct en50221_app_send_functions *funcs); +extern struct en50221_app_datetime + *en50221_app_datetime_create(struct en50221_app_send_functions *funcs); /** * Destroy an instance of the datetime resource. * * @param datetime Instance to destroy. */ -extern void en50221_app_datetime_destroy(en50221_app_datetime datetime); +extern void en50221_app_datetime_destroy(struct en50221_app_datetime *datetime); /** * Register the callback for when we receive a enquiry request. @@ -74,8 +76,9 @@ extern void en50221_app_datetime_destroy(en50221_app_datetime datetime); * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_app_datetime_register_enquiry_callback(en50221_app_datetime datetime, - en50221_app_datetime_enquiry_callback callback, void *arg); +extern void en50221_app_datetime_register_enquiry_callback(struct en50221_app_datetime *datetime, + en50221_app_datetime_enquiry_callback callback, + void *arg); /** * Send the time to the CAM. @@ -87,10 +90,10 @@ extern void en50221_app_datetime_register_enquiry_callback(en50221_app_datetime * UTC and local time in minutes. * @return 0 on success, -1 on failure. */ -extern int en50221_app_datetime_send(en50221_app_datetime datetime, - uint16_t session_number, - time_t utc_time, - int time_offset); +extern int en50221_app_datetime_send(struct en50221_app_datetime *datetime, + uint16_t session_number, + time_t utc_time, + int time_offset); /** * Pass data received for this resource into it for parsing. @@ -103,14 +106,14 @@ extern int en50221_app_datetime_send(en50221_app_datetime datetime, * @param data_length Length of data in bytes. * @return 0 on success, -1 on failure. */ -extern int en50221_app_datetime_message(en50221_app_datetime datetime, - uint8_t slot_id, - uint16_t session_number, - uint32_t resource_id, - uint8_t *data, uint32_t data_length); +extern int en50221_app_datetime_message(struct en50221_app_datetime *datetime, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, + uint32_t data_length); #ifdef __cplusplus } #endif - #endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_dvb.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_dvb.c index dfda1bf..21b2bec 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_dvb.c +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_dvb.c @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,7 +18,7 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <string.h> @@ -28,137 +28,144 @@ #include "en50221_app_tags.h" #include "asn_1.h" -struct en50221_app_dvb_private { - struct en50221_app_send_functions *funcs; +struct en50221_app_dvb { + struct en50221_app_send_functions *funcs; - en50221_app_dvb_tune_callback tune_callback; - void *tune_callback_arg; + en50221_app_dvb_tune_callback tune_callback; + void *tune_callback_arg; - en50221_app_dvb_replace_callback replace_callback; - void *replace_callback_arg; + en50221_app_dvb_replace_callback replace_callback; + void *replace_callback_arg; - en50221_app_dvb_clear_replace_callback clear_replace_callback; - void *clear_replace_callback_arg; + en50221_app_dvb_clear_replace_callback clear_replace_callback; + void *clear_replace_callback_arg; - pthread_mutex_t lock; + pthread_mutex_t lock; }; -static int en50221_app_dvb_parse_tune(struct en50221_app_dvb_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length); +static int en50221_app_dvb_parse_tune(struct en50221_app_dvb *dvb, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length); -static int en50221_app_dvb_parse_replace(struct en50221_app_dvb_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length); +static int en50221_app_dvb_parse_replace(struct en50221_app_dvb *dvb, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length); -static int en50221_app_dvb_parse_clear_replace(struct en50221_app_dvb_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length); +static int en50221_app_dvb_parse_clear_replace(struct en50221_app_dvb *dvb, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length); -en50221_app_dvb en50221_app_dvb_create(struct en50221_app_send_functions *funcs) +struct en50221_app_dvb *en50221_app_dvb_create(struct en50221_app_send_functions *funcs) { - struct en50221_app_dvb_private *private = NULL; - - // create structure and set it up - private = malloc(sizeof(struct en50221_app_dvb_private)); - if (private == NULL) { - return NULL; - } - private->funcs = funcs; - private->tune_callback = NULL; - private->replace_callback = NULL; - private->clear_replace_callback = NULL; - - pthread_mutex_init(&private->lock, NULL); - - // done - return private; + struct en50221_app_dvb *dvb = NULL; + + // create structure and set it up + dvb = malloc(sizeof(struct en50221_app_dvb)); + if (dvb == NULL) { + return NULL; + } + dvb->funcs = funcs; + dvb->tune_callback = NULL; + dvb->replace_callback = NULL; + dvb->clear_replace_callback = NULL; + + pthread_mutex_init(&dvb->lock, NULL); + + // done + return dvb; } -void en50221_app_dvb_destroy(en50221_app_dvb dvb) +void en50221_app_dvb_destroy(struct en50221_app_dvb *dvb) { - struct en50221_app_dvb_private *private = (struct en50221_app_dvb_private *) dvb; - - pthread_mutex_destroy(&private->lock); - free(private); + pthread_mutex_destroy(&dvb->lock); + free(dvb); } -void en50221_app_dvb_register_tune_callback(en50221_app_dvb dvb, - en50221_app_dvb_tune_callback callback, void *arg) +void en50221_app_dvb_register_tune_callback(struct en50221_app_dvb *dvb, + en50221_app_dvb_tune_callback callback, + void *arg) { - struct en50221_app_dvb_private *private = (struct en50221_app_dvb_private *) dvb; - - pthread_mutex_lock(&private->lock); - private->tune_callback = callback; - private->tune_callback_arg = arg; - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&dvb->lock); + dvb->tune_callback = callback; + dvb->tune_callback_arg = arg; + pthread_mutex_unlock(&dvb->lock); } -void en50221_app_dvb_register_replace_callback(en50221_app_dvb dvb, - en50221_app_dvb_replace_callback callback, void *arg) +void en50221_app_dvb_register_replace_callback(struct en50221_app_dvb *dvb, + en50221_app_dvb_replace_callback callback, + void *arg) { - struct en50221_app_dvb_private *private = (struct en50221_app_dvb_private *) dvb; - - pthread_mutex_lock(&private->lock); - private->replace_callback = callback; - private->replace_callback_arg = arg; - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&dvb->lock); + dvb->replace_callback = callback; + dvb->replace_callback_arg = arg; + pthread_mutex_unlock(&dvb->lock); } -void en50221_app_dvb_register_clear_replace_callback(en50221_app_dvb dvb, - en50221_app_dvb_clear_replace_callback callback, void *arg) +void en50221_app_dvb_register_clear_replace_callback(struct en50221_app_dvb *dvb, + en50221_app_dvb_clear_replace_callback callback, + void *arg) { - struct en50221_app_dvb_private *private = (struct en50221_app_dvb_private *) dvb; - - pthread_mutex_lock(&private->lock); - private->clear_replace_callback = callback; - private->clear_replace_callback_arg = arg; - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&dvb->lock); + dvb->clear_replace_callback = callback; + dvb->clear_replace_callback_arg = arg; + pthread_mutex_unlock(&dvb->lock); } -int en50221_app_dvb_ask_release(en50221_app_dvb dvb, uint16_t session_number) +int en50221_app_dvb_ask_release(struct en50221_app_dvb *dvb, + uint16_t session_number) { - struct en50221_app_dvb_private *private = (struct en50221_app_dvb_private *) dvb; - uint8_t data[4]; + uint8_t data[4]; - data[0] = (TAG_ASK_RELEASE >> 16) & 0xFF; - data[1] = (TAG_ASK_RELEASE >> 8) & 0xFF; - data[2] = TAG_ASK_RELEASE & 0xFF; - data[3] = 0; + data[0] = (TAG_ASK_RELEASE >> 16) & 0xFF; + data[1] = (TAG_ASK_RELEASE >> 8) & 0xFF; + data[2] = TAG_ASK_RELEASE & 0xFF; + data[3] = 0; - return private->funcs->send_data(private->funcs->arg, session_number, data, 4); + return dvb->funcs->send_data(dvb->funcs->arg, session_number, data, 4); } -int en50221_app_dvb_message(en50221_app_dvb dvb, - uint8_t slot_id, - uint16_t session_number, - uint32_t resource_id, - uint8_t *data, uint32_t data_length) +int en50221_app_dvb_message(struct en50221_app_dvb *dvb, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t * data, uint32_t data_length) { - struct en50221_app_dvb_private *private = (struct en50221_app_dvb_private *) dvb; - (void) resource_id; - - // get the tag - if (data_length < 3) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; - - switch(tag) - { - case TAG_TUNE: - return en50221_app_dvb_parse_tune(private, slot_id, session_number, data+3, data_length-3); - case TAG_REPLACE: - return en50221_app_dvb_parse_replace(private, slot_id, session_number, data+3, data_length-3); - case TAG_CLEAR_REPLACE: - return en50221_app_dvb_parse_clear_replace(private, slot_id, session_number, data+3, data_length-3); - } - - print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); - return -1; + (void) resource_id; + + // get the tag + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; + + switch (tag) { + case TAG_TUNE: + return en50221_app_dvb_parse_tune(dvb, slot_id, + session_number, data + 3, + data_length - 3); + case TAG_REPLACE: + return en50221_app_dvb_parse_replace(dvb, slot_id, + session_number, + data + 3, + data_length - 3); + case TAG_CLEAR_REPLACE: + return en50221_app_dvb_parse_clear_replace(dvb, slot_id, + session_number, + data + 3, + data_length - 3); + } + + print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); + return -1; } @@ -170,94 +177,106 @@ int en50221_app_dvb_message(en50221_app_dvb dvb, -static int en50221_app_dvb_parse_tune(struct en50221_app_dvb_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length) +static int en50221_app_dvb_parse_tune(struct en50221_app_dvb *dvb, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, uint32_t data_length) { - // validate data - if (data_length < 9) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - if (data[0] != 8) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - uint8_t *tune_data = data+1; - - // parse it - uint16_t network_id = (tune_data[0] << 8) | tune_data[1]; - uint16_t original_network_id = (tune_data[2] << 8) | tune_data[3]; - uint16_t transport_stream_id = (tune_data[4] << 8) | tune_data[5]; - uint16_t service_id = (tune_data[6] << 8) | tune_data[7]; - - // tell the app - pthread_mutex_lock(&private->lock); - en50221_app_dvb_tune_callback cb = private->tune_callback; - void *cb_arg = private->tune_callback_arg; - pthread_mutex_unlock(&private->lock); - if (cb) { - return cb(cb_arg, slot_id, session_number, network_id, original_network_id, transport_stream_id, service_id); - } - return 0; + // validate data + if (data_length < 9) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (data[0] != 8) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint8_t *tune_data = data + 1; + + // parse it + uint16_t network_id = (tune_data[0] << 8) | tune_data[1]; + uint16_t original_network_id = (tune_data[2] << 8) | tune_data[3]; + uint16_t transport_stream_id = (tune_data[4] << 8) | tune_data[5]; + uint16_t service_id = (tune_data[6] << 8) | tune_data[7]; + + // tell the app + pthread_mutex_lock(&dvb->lock); + en50221_app_dvb_tune_callback cb = dvb->tune_callback; + void *cb_arg = dvb->tune_callback_arg; + pthread_mutex_unlock(&dvb->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, network_id, + original_network_id, transport_stream_id, + service_id); + } + return 0; } -static int en50221_app_dvb_parse_replace(struct en50221_app_dvb_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length) +static int en50221_app_dvb_parse_replace(struct en50221_app_dvb *dvb, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length) { - // validate data - if (data_length < 6) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - if (data[0] != 5) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - uint8_t *replace_data = data+1; - - // parse it - uint8_t replacement_ref = replace_data[0]; - uint16_t replace_pid = ((replace_data[1] & 0x1f)<<8) | replace_data[2]; - uint16_t replacement_pid = ((replace_data[3] & 0x1f)<<8) | replace_data[4]; - - // tell the app - pthread_mutex_lock(&private->lock); - en50221_app_dvb_replace_callback cb = private->replace_callback; - void *cb_arg = private->replace_callback_arg; - pthread_mutex_unlock(&private->lock); - if (cb) { - return cb(cb_arg, slot_id, session_number, replacement_ref, replace_pid, replacement_pid); - } - return 0; + // validate data + if (data_length < 6) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (data[0] != 5) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint8_t *replace_data = data + 1; + + // parse it + uint8_t replacement_ref = replace_data[0]; + uint16_t replace_pid = + ((replace_data[1] & 0x1f) << 8) | replace_data[2]; + uint16_t replacement_pid = + ((replace_data[3] & 0x1f) << 8) | replace_data[4]; + + // tell the app + pthread_mutex_lock(&dvb->lock); + en50221_app_dvb_replace_callback cb = dvb->replace_callback; + void *cb_arg = dvb->replace_callback_arg; + pthread_mutex_unlock(&dvb->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, replacement_ref, + replace_pid, replacement_pid); + } + return 0; } -static int en50221_app_dvb_parse_clear_replace(struct en50221_app_dvb_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length) +static int en50221_app_dvb_parse_clear_replace(struct en50221_app_dvb *dvb, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length) { - // validate data - if (data_length < 2) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - if (data[0] != 1) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - uint8_t *replace_data = data+1; - - // parse it - uint8_t replacement_ref = replace_data[0]; - - // tell the app - pthread_mutex_lock(&private->lock); - en50221_app_dvb_clear_replace_callback cb = private->clear_replace_callback; - void *cb_arg = private->clear_replace_callback_arg; - pthread_mutex_unlock(&private->lock); - if (cb) { - return cb(cb_arg, slot_id, session_number, replacement_ref); - } - return 0; + // validate data + if (data_length < 2) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (data[0] != 1) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint8_t *replace_data = data + 1; + + // parse it + uint8_t replacement_ref = replace_data[0]; + + // tell the app + pthread_mutex_lock(&dvb->lock); + en50221_app_dvb_clear_replace_callback cb = + dvb->clear_replace_callback; + void *cb_arg = dvb->clear_replace_callback_arg; + pthread_mutex_unlock(&dvb->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, + replacement_ref); + } + return 0; } diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_dvb.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_dvb.h index 7830942..be74e6b 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_dvb.h +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_dvb.h @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,15 +18,14 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __EN50221_APPLICATION_DVB_H__ #define __EN50221_APPLICATION_DVB_H__ #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif #include <stdlib.h> @@ -48,9 +47,13 @@ extern "C" * @param service_id Service id requested by CAM. * @return 0 on success, -1 on failure. */ -typedef int (*en50221_app_dvb_tune_callback)(void *arg, uint8_t slot_id, uint16_t session_number, - uint16_t network_id, uint32_t original_network_id, - uint16_t transport_stream_id, uint16_t service_id); +typedef int (*en50221_app_dvb_tune_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number, + uint16_t network_id, + uint32_t original_network_id, + uint16_t transport_stream_id, + uint16_t service_id); /** * Type definition for replace - called when we receive a replace request from a CAM. @@ -63,9 +66,12 @@ typedef int (*en50221_app_dvb_tune_callback)(void *arg, uint8_t slot_id, uint16_ * @param replacement_pid PID to replace it with. * @return 0 on success, -1 on failure. */ -typedef int (*en50221_app_dvb_replace_callback)(void *arg, uint8_t slot_id, uint16_t session_number, - uint8_t replacement_ref, - uint16_t replaced_pid, uint16_t replacement_pid); +typedef int (*en50221_app_dvb_replace_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number, + uint8_t replacement_ref, + uint16_t replaced_pid, + uint16_t replacement_pid); /** @@ -77,14 +83,16 @@ typedef int (*en50221_app_dvb_replace_callback)(void *arg, uint8_t slot_id, uint * @param replacement_ref Replacement ref. * @return 0 on success, -1 on failure. */ -typedef int (*en50221_app_dvb_clear_replace_callback)(void *arg, uint8_t slot_id, uint16_t session_number, - uint8_t replacement_ref); +typedef int (*en50221_app_dvb_clear_replace_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number, + uint8_t replacement_ref); /** * Opaque type representing a dvb resource. */ -typedef void *en50221_app_dvb; +struct en50221_app_dvb; /** * Create an instance of the dvb resource. @@ -92,14 +100,14 @@ typedef void *en50221_app_dvb; * @param funcs Send functions to use. * @return Instance, or NULL on failure. */ -extern en50221_app_dvb en50221_app_dvb_create(struct en50221_app_send_functions *funcs); +extern struct en50221_app_dvb *en50221_app_dvb_create(struct en50221_app_send_functions *funcs); /** * Destroy an instance of the dvb resource. * * @param dvb Instance to destroy. */ -extern void en50221_app_dvb_destroy(en50221_app_dvb dvb); +extern void en50221_app_dvb_destroy(struct en50221_app_dvb *dvb); /** * Register the callback for when we receive a tune request. @@ -108,8 +116,9 @@ extern void en50221_app_dvb_destroy(en50221_app_dvb dvb); * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_app_dvb_register_tune_callback(en50221_app_dvb dvb, - en50221_app_dvb_tune_callback callback, void *arg); +extern void en50221_app_dvb_register_tune_callback(struct en50221_app_dvb *dvb, + en50221_app_dvb_tune_callback callback, + void *arg); /** * Register the callback for when we receive a replace request. @@ -118,8 +127,9 @@ extern void en50221_app_dvb_register_tune_callback(en50221_app_dvb dvb, * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_app_dvb_register_replace_callback(en50221_app_dvb dvb, - en50221_app_dvb_replace_callback callback, void *arg); +extern void en50221_app_dvb_register_replace_callback(struct en50221_app_dvb *dvb, + en50221_app_dvb_replace_callback callback, + void *arg); /** * Register the callback for when we receive a clear replace request. @@ -128,8 +138,9 @@ extern void en50221_app_dvb_register_replace_callback(en50221_app_dvb dvb, * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_app_dvb_register_clear_replace_callback(en50221_app_dvb dvb, - en50221_app_dvb_clear_replace_callback callback, void *arg); +extern void en50221_app_dvb_register_clear_replace_callback(struct en50221_app_dvb *dvb, + en50221_app_dvb_clear_replace_callback callback, + void *arg); /** * Send an ask release request to the CAM. @@ -138,7 +149,8 @@ extern void en50221_app_dvb_register_clear_replace_callback(en50221_app_dvb dvb, * @param session_number Session number to send it on. * @return 0 on success, -1 on failure. */ -extern int en50221_app_dvb_ask_release(en50221_app_dvb dvb, uint16_t session_number); +extern int en50221_app_dvb_ask_release(struct en50221_app_dvb *dvb, + uint16_t session_number); /** * Pass data received for this resource into it for parsing. @@ -151,14 +163,14 @@ extern int en50221_app_dvb_ask_release(en50221_app_dvb dvb, uint16_t session_num * @param data_length Length of data in bytes. * @return 0 on success, -1 on failure. */ -extern int en50221_app_dvb_message(en50221_app_dvb dvb, - uint8_t slot_id, - uint16_t session_number, - uint32_t resource_id, - uint8_t *data, uint32_t data_length); +extern int en50221_app_dvb_message(struct en50221_app_dvb *dvb, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, + uint32_t data_length); #ifdef __cplusplus } #endif - #endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_epg.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_epg.c index 7237476..87b4743 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_epg.c +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_epg.c @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,7 +18,7 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <string.h> @@ -29,138 +29,139 @@ #include "en50221_app_tags.h" #include "asn_1.h" -struct en50221_app_epg_private { - struct en50221_app_send_functions *funcs; +struct en50221_app_epg { + struct en50221_app_send_functions *funcs; - en50221_app_epg_reply_callback callback; - void *callback_arg; + en50221_app_epg_reply_callback callback; + void *callback_arg; - pthread_mutex_t lock; + pthread_mutex_t lock; }; -static int en50221_app_epg_parse_reply(struct en50221_app_epg_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length); +static int en50221_app_epg_parse_reply(struct en50221_app_epg *private, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length); -en50221_app_epg en50221_app_epg_create(struct en50221_app_send_functions *funcs) +struct en50221_app_epg *en50221_app_epg_create(struct en50221_app_send_functions *funcs) { - struct en50221_app_epg_private *private = NULL; + struct en50221_app_epg *epg = NULL; - // create structure and set it up - private = malloc(sizeof(struct en50221_app_epg_private)); - if (private == NULL) { - return NULL; - } - private->funcs = funcs; - private->callback = NULL; + // create structure and set it up + epg = malloc(sizeof(struct en50221_app_epg)); + if (epg == NULL) { + return NULL; + } + epg->funcs = funcs; + epg->callback = NULL; - pthread_mutex_init(&private->lock, NULL); + pthread_mutex_init(&epg->lock, NULL); - // done - return private; + // done + return epg; } -void en50221_app_epg_destroy(en50221_app_epg epg) +void en50221_app_epg_destroy(struct en50221_app_epg *epg) { - struct en50221_app_epg_private *private = (struct en50221_app_epg_private *) epg; - - pthread_mutex_destroy(&private->lock); - free(private); + pthread_mutex_destroy(&epg->lock); + free(epg); } -void en50221_app_epg_register_enquiry_callback(en50221_app_epg epg, - en50221_app_epg_reply_callback callback, void *arg) +void en50221_app_epg_register_enquiry_callback(struct en50221_app_epg *epg, + en50221_app_epg_reply_callback callback, + void *arg) { - struct en50221_app_epg_private *private = (struct en50221_app_epg_private *) epg; - - pthread_mutex_lock(&private->lock); - private->callback = callback; - private->callback_arg = arg; - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&epg->lock); + epg->callback = callback; + epg->callback_arg = arg; + pthread_mutex_unlock(&epg->lock); } -int en50221_app_epg_enquire(en50221_app_epg epg, - uint16_t session_number, - uint8_t command_id, - uint16_t network_id, - uint16_t original_network_id, - uint16_t transport_stream_id, - uint16_t service_id, - uint16_t event_id) +int en50221_app_epg_enquire(struct en50221_app_epg *epg, + uint16_t session_number, + uint8_t command_id, + uint16_t network_id, + uint16_t original_network_id, + uint16_t transport_stream_id, + uint16_t service_id, uint16_t event_id) { - struct en50221_app_epg_private *private = (struct en50221_app_epg_private *) epg; - uint8_t data[15]; - - data[0] = (TAG_EPG_ENQUIRY >> 16) & 0xFF; - data[1] = (TAG_EPG_ENQUIRY >> 8) & 0xFF; - data[2] = TAG_EPG_ENQUIRY & 0xFF; - data[3] = 11; - data[4] = command_id; - data[5] = network_id >> 8; - data[6] = network_id; - data[7] = original_network_id >> 8; - data[8] = original_network_id; - data[9] = transport_stream_id >> 8; - data[10] = transport_stream_id; - data[11] = service_id >> 8; - data[12] = service_id; - data[13] = event_id >> 8; - data[14] = event_id; - return private->funcs->send_data(private->funcs->arg, session_number, data, 15); + uint8_t data[15]; + + data[0] = (TAG_EPG_ENQUIRY >> 16) & 0xFF; + data[1] = (TAG_EPG_ENQUIRY >> 8) & 0xFF; + data[2] = TAG_EPG_ENQUIRY & 0xFF; + data[3] = 11; + data[4] = command_id; + data[5] = network_id >> 8; + data[6] = network_id; + data[7] = original_network_id >> 8; + data[8] = original_network_id; + data[9] = transport_stream_id >> 8; + data[10] = transport_stream_id; + data[11] = service_id >> 8; + data[12] = service_id; + data[13] = event_id >> 8; + data[14] = event_id; + return epg->funcs->send_data(epg->funcs->arg, session_number, data, 15); } -int en50221_app_epg_message(en50221_app_epg epg, - uint8_t slot_id, - uint16_t session_number, - uint32_t resource_id, - uint8_t *data, uint32_t data_length) +int en50221_app_epg_message(struct en50221_app_epg *epg, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t * data, uint32_t data_length) { - struct en50221_app_epg_private *private = (struct en50221_app_epg_private *) epg; - (void) resource_id; - - // get the tag - if (data_length < 3) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; - - switch(tag) - { - case TAG_EPG_REPLY: - return en50221_app_epg_parse_reply(private, slot_id, session_number, data+3, data_length-3); - } - - print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); - return -1; + struct en50221_app_epg *private = (struct en50221_app_epg *) epg; + (void) resource_id; + + // get the tag + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; + + switch (tag) { + case TAG_EPG_REPLY: + return en50221_app_epg_parse_reply(private, slot_id, + session_number, + data + 3, + data_length - 3); + } + + print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); + return -1; } -static int en50221_app_epg_parse_reply(struct en50221_app_epg_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length) +static int en50221_app_epg_parse_reply(struct en50221_app_epg *epg, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length) { - // validate data - if (data_length != 2) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - if (data[0] != 1) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - uint8_t event_status = data[1]; - - // tell the app - pthread_mutex_lock(&private->lock); - en50221_app_epg_reply_callback cb = private->callback; - void *cb_arg = private->callback_arg; - pthread_mutex_unlock(&private->lock); - if (cb) { - return cb(cb_arg, slot_id, session_number, event_status); - } - return 0; + // validate data + if (data_length != 2) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (data[0] != 1) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint8_t event_status = data[1]; + + // tell the app + pthread_mutex_lock(&epg->lock); + en50221_app_epg_reply_callback cb = epg->callback; + void *cb_arg = epg->callback_arg; + pthread_mutex_unlock(&epg->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, event_status); + } + return 0; } diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_epg.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_epg.h index dcc65f1..dcfe9da 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_epg.h +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_epg.h @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,15 +18,14 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __EN50221_APPLICATION_epg_H__ #define __EN50221_APPLICATION_epg_H__ #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif #include <stdlib.h> @@ -57,13 +56,15 @@ extern "C" * @param event_status One of the EPG_EVENTSTATUS_* values. * @return 0 on success, -1 on failure. */ -typedef int (*en50221_app_epg_reply_callback)(void *arg, uint8_t slot_id, uint16_t session_number, - uint8_t event_status); +typedef int (*en50221_app_epg_reply_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number, + uint8_t event_status); /** * Opaque type representing a epg resource. */ -typedef void *en50221_app_epg; +struct en50221_app_epg; /** * Create an instance of the epg resource. @@ -71,14 +72,14 @@ typedef void *en50221_app_epg; * @param funcs Send functions to use. * @return Instance, or NULL on failure. */ -extern en50221_app_epg en50221_app_epg_create(struct en50221_app_send_functions *funcs); +extern struct en50221_app_epg *en50221_app_epg_create(struct en50221_app_send_functions *funcs); /** * Destroy an instance of the epg resource. * * @param epg Instance to destroy. */ -extern void en50221_app_epg_destroy(en50221_app_epg epg); +extern void en50221_app_epg_destroy(struct en50221_app_epg *epg); /** * Register the callback for when we receive a enquiry response. @@ -87,8 +88,9 @@ extern void en50221_app_epg_destroy(en50221_app_epg epg); * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_app_epg_register_reply_callback(en50221_app_epg epg, - en50221_app_epg_reply_callback callback, void *arg); +extern void en50221_app_epg_register_reply_callback(struct en50221_app_epg *epg, + en50221_app_epg_reply_callback callback, + void *arg); /** * Enquire about the entitlement status for an EPG entry. @@ -103,14 +105,14 @@ extern void en50221_app_epg_register_reply_callback(en50221_app_epg epg, * @param event_id Event ID concerned. * @return 0 on success, -1 on failure. */ -extern int en50221_app_epg_enquire(en50221_app_epg epg, - uint16_t session_number, - uint8_t command_id, - uint16_t network_id, - uint16_t original_network_id, - uint16_t transport_stream_id, - uint16_t service_id, - uint16_t event_id); +extern int en50221_app_epg_enquire(struct en50221_app_epg *epg, + uint16_t session_number, + uint8_t command_id, + uint16_t network_id, + uint16_t original_network_id, + uint16_t transport_stream_id, + uint16_t service_id, + uint16_t event_id); /** * Pass data received for this resource into it for parsing. @@ -123,14 +125,14 @@ extern int en50221_app_epg_enquire(en50221_app_epg epg, * @param data_length Length of data in bytes. * @return 0 on success, -1 on failure. */ -extern int en50221_app_epg_message(en50221_app_epg epg, - uint8_t slot_id, - uint16_t session_number, - uint32_t resource_id, - uint8_t *data, uint32_t data_length); +extern int en50221_app_epg_message(struct en50221_app_epg *epg, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, + uint32_t data_length); #ifdef __cplusplus } #endif - #endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_lowspeed.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_lowspeed.c index 68d9774..a66598a 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_lowspeed.c +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_lowspeed.c @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,7 +18,7 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <string.h> @@ -29,486 +29,505 @@ #include "asn_1.h" struct en50221_app_lowspeed_session { - uint16_t session_number; - uint8_t *block_chain; - uint32_t block_length; + uint16_t session_number; + uint8_t *block_chain; + uint32_t block_length; - struct en50221_app_lowspeed_session *next; + struct en50221_app_lowspeed_session *next; }; -struct en50221_app_lowspeed_private { - struct en50221_app_send_functions *funcs; +struct en50221_app_lowspeed { + struct en50221_app_send_functions *funcs; - en50221_app_lowspeed_command_callback command_callback; - void *command_callback_arg; + en50221_app_lowspeed_command_callback command_callback; + void *command_callback_arg; - en50221_app_lowspeed_send_callback send_callback; - void *send_callback_arg; + en50221_app_lowspeed_send_callback send_callback; + void *send_callback_arg; - struct en50221_app_lowspeed_session *sessions; + struct en50221_app_lowspeed_session *sessions; - pthread_mutex_t lock; + pthread_mutex_t lock; }; static int en50221_app_lowspeed_parse_connect_on_channel(struct en50221_app_lowspeed_command *command, - uint8_t *data, - int data_length); -static int en50221_app_lowspeed_parse_command(struct en50221_app_lowspeed_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length); -static int en50221_app_lowspeed_parse_send(struct en50221_app_lowspeed_private *private, - uint8_t slot_id, uint16_t session_number, int more_last, - uint8_t *data, uint32_t data_length); - - - -en50221_app_lowspeed en50221_app_lowspeed_create(struct en50221_app_send_functions *funcs) + uint8_t *data, + int data_length); +static int en50221_app_lowspeed_parse_command(struct en50221_app_lowspeed *lowspeed, + uint8_t slot_id, + uint16_t session_number, + uint8_t *data, + uint32_t data_length); +static int en50221_app_lowspeed_parse_send(struct en50221_app_lowspeed *lowspeed, + uint8_t slot_id, + uint16_t session_number, + int more_last, + uint8_t *data, + uint32_t data_length); + + + +struct en50221_app_lowspeed *en50221_app_lowspeed_create(struct en50221_app_send_functions *funcs) { - struct en50221_app_lowspeed_private *private = NULL; - - // create structure and set it up - private = malloc(sizeof(struct en50221_app_lowspeed_private)); - if (private == NULL) { - return NULL; - } - private->funcs = funcs; - private->command_callback = NULL; - private->send_callback = NULL; - private->sessions = NULL; - - pthread_mutex_init(&private->lock, NULL); - - // done - return private; + struct en50221_app_lowspeed *lowspeed = NULL; + + // create structure and set it up + lowspeed = malloc(sizeof(struct en50221_app_lowspeed)); + if (lowspeed == NULL) { + return NULL; + } + lowspeed->funcs = funcs; + lowspeed->command_callback = NULL; + lowspeed->send_callback = NULL; + lowspeed->sessions = NULL; + + pthread_mutex_init(&lowspeed->lock, NULL); + + // done + return lowspeed; } -void en50221_app_lowspeed_destroy(en50221_app_lowspeed lowspeed) +void en50221_app_lowspeed_destroy(struct en50221_app_lowspeed *lowspeed) { - struct en50221_app_lowspeed_private *private = (struct en50221_app_lowspeed_private *) lowspeed; - - struct en50221_app_lowspeed_session *cur_s = private->sessions; - while(cur_s) { - struct en50221_app_lowspeed_session *next = cur_s->next; - if (cur_s->block_chain) - free(cur_s->block_chain); - free(cur_s); - cur_s = next; - } - - pthread_mutex_destroy(&private->lock); - free(private); + struct en50221_app_lowspeed_session *cur_s = lowspeed->sessions; + while (cur_s) { + struct en50221_app_lowspeed_session *next = cur_s->next; + if (cur_s->block_chain) + free(cur_s->block_chain); + free(cur_s); + cur_s = next; + } + + pthread_mutex_destroy(&lowspeed->lock); + free(lowspeed); } -void en50221_app_lowspeed_clear_session(en50221_app_lowspeed lowspeed, uint16_t session_number) +void en50221_app_lowspeed_clear_session(struct en50221_app_lowspeed *lowspeed, + uint16_t session_number) { - struct en50221_app_lowspeed_private *private = (struct en50221_app_lowspeed_private *) lowspeed; - - pthread_mutex_lock(&private->lock); - struct en50221_app_lowspeed_session *cur_s = private->sessions; - struct en50221_app_lowspeed_session *prev_s = NULL; - while(cur_s) { - if (cur_s->session_number == session_number) { - if (cur_s->block_chain) - free(cur_s->block_chain); - if (prev_s) { - prev_s->next = cur_s->next; - } else { - private->sessions = cur_s->next; - } - free(cur_s); - return; - } - - prev_s = cur_s; - cur_s=cur_s->next; - } - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&lowspeed->lock); + struct en50221_app_lowspeed_session *cur_s = lowspeed->sessions; + struct en50221_app_lowspeed_session *prev_s = NULL; + while (cur_s) { + if (cur_s->session_number == session_number) { + if (cur_s->block_chain) + free(cur_s->block_chain); + if (prev_s) { + prev_s->next = cur_s->next; + } else { + lowspeed->sessions = cur_s->next; + } + free(cur_s); + return; + } + + prev_s = cur_s; + cur_s = cur_s->next; + } + pthread_mutex_unlock(&lowspeed->lock); } -void en50221_app_lowspeed_register_command_callback(en50221_app_lowspeed lowspeed, - en50221_app_lowspeed_command_callback callback, void *arg) +void en50221_app_lowspeed_register_command_callback(struct en50221_app_lowspeed *lowspeed, + en50221_app_lowspeed_command_callback callback, + void *arg) { - struct en50221_app_lowspeed_private *private = (struct en50221_app_lowspeed_private *) lowspeed; - - pthread_mutex_lock(&private->lock); - private->command_callback = callback; - private->command_callback_arg = arg; - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&lowspeed->lock); + lowspeed->command_callback = callback; + lowspeed->command_callback_arg = arg; + pthread_mutex_unlock(&lowspeed->lock); } -void en50221_app_lowspeed_register_send_callback(en50221_app_lowspeed lowspeed, - en50221_app_lowspeed_send_callback callback, void *arg) +void en50221_app_lowspeed_register_send_callback(struct en50221_app_lowspeed *lowspeed, + en50221_app_lowspeed_send_callback callback, + void *arg) { - struct en50221_app_lowspeed_private *private = (struct en50221_app_lowspeed_private *) lowspeed; - - pthread_mutex_lock(&private->lock); - private->send_callback = callback; - private->send_callback_arg = arg; - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&lowspeed->lock); + lowspeed->send_callback = callback; + lowspeed->send_callback_arg = arg; + pthread_mutex_unlock(&lowspeed->lock); } -int en50221_app_lowspeed_send_comms_reply(en50221_app_lowspeed lowspeed, - uint16_t session_number, - uint8_t comms_reply_id, - uint8_t return_value) +int en50221_app_lowspeed_send_comms_reply(struct en50221_app_lowspeed *lowspeed, + uint16_t session_number, + uint8_t comms_reply_id, + uint8_t return_value) { - struct en50221_app_lowspeed_private *private = (struct en50221_app_lowspeed_private *) lowspeed; - uint8_t data[6]; - - data[0] = (TAG_COMMS_REPLY >> 16) & 0xFF; - data[1] = (TAG_COMMS_REPLY >> 8) & 0xFF; - data[2] = TAG_COMMS_REPLY & 0xFF; - data[3] = 2; - data[4] = comms_reply_id; - data[5] = return_value; - return private->funcs->send_data(private->funcs->arg, session_number, data, 6); + uint8_t data[6]; + + data[0] = (TAG_COMMS_REPLY >> 16) & 0xFF; + data[1] = (TAG_COMMS_REPLY >> 8) & 0xFF; + data[2] = TAG_COMMS_REPLY & 0xFF; + data[3] = 2; + data[4] = comms_reply_id; + data[5] = return_value; + return lowspeed->funcs->send_data(lowspeed->funcs->arg, + session_number, data, 6); } -int en50221_app_lowspeed_send_comms_data(en50221_app_lowspeed lowspeed, - uint16_t session_number, - uint8_t phase_id, - uint32_t tx_data_length, - uint8_t *tx_data) +int en50221_app_lowspeed_send_comms_data(struct en50221_app_lowspeed *lowspeed, + uint16_t session_number, + uint8_t phase_id, + uint32_t tx_data_length, + uint8_t * tx_data) { - struct en50221_app_lowspeed_private *private = (struct en50221_app_lowspeed_private *) lowspeed; - uint8_t buf[10]; - - // the spec defines this limit - if (tx_data_length > 254) { - return -1; - } - - // set up the tag - buf[0] = (TAG_COMMS_RECV_LAST >> 16) & 0xFF; - buf[1] = (TAG_COMMS_RECV_LAST >> 8) & 0xFF; - buf[2] = TAG_COMMS_RECV_LAST & 0xFF; - - // encode the length field - int length_field_len; - if ((length_field_len = asn_1_encode(tx_data_length+1, buf+3, 3)) < 0) { - return -1; - } - - // the phase_id - buf[3+length_field_len] = phase_id; - - // build the iovecs - struct iovec iov[2]; - iov[0].iov_base = buf; - iov[0].iov_len = 3+length_field_len+1; - iov[1].iov_base = tx_data; - iov[1].iov_len = tx_data_length; - - // create the data and send it - return private->funcs->send_datav(private->funcs->arg, session_number, iov, 2); + uint8_t buf[10]; + + // the spec defines this limit + if (tx_data_length > 254) { + return -1; + } + // set up the tag + buf[0] = (TAG_COMMS_RECV_LAST >> 16) & 0xFF; + buf[1] = (TAG_COMMS_RECV_LAST >> 8) & 0xFF; + buf[2] = TAG_COMMS_RECV_LAST & 0xFF; + + // encode the length field + int length_field_len; + if ((length_field_len = asn_1_encode(tx_data_length + 1, buf + 3, 3)) < 0) { + return -1; + } + // the phase_id + buf[3 + length_field_len] = phase_id; + + // build the iovecs + struct iovec iov[2]; + iov[0].iov_base = buf; + iov[0].iov_len = 3 + length_field_len + 1; + iov[1].iov_base = tx_data; + iov[1].iov_len = tx_data_length; + + // create the data and send it + return lowspeed->funcs->send_datav(lowspeed->funcs->arg, + session_number, iov, 2); } -int en50221_app_lowspeed_message(en50221_app_lowspeed lowspeed, - uint8_t slot_id, - uint16_t session_number, - uint32_t resource_id, - uint8_t *data, uint32_t data_length) +int en50221_app_lowspeed_message(struct en50221_app_lowspeed *lowspeed, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t * data, uint32_t data_length) { - struct en50221_app_lowspeed_private *private = (struct en50221_app_lowspeed_private *) lowspeed; - (void)resource_id; - - // get the tag - if (data_length < 3) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; - - switch(tag) - { - case TAG_COMMS_COMMAND: - return en50221_app_lowspeed_parse_command(private, slot_id, session_number, data+3, data_length-3); - case TAG_COMMS_SEND_LAST: - return en50221_app_lowspeed_parse_send(private, slot_id, session_number, 1, data+3, data_length-3); - case TAG_COMMS_SEND_MORE: - return en50221_app_lowspeed_parse_send(private, slot_id, session_number, 0, data+3, data_length-3); - } - - print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); - return -1; + (void) resource_id; + + // get the tag + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; + + switch (tag) { + case TAG_COMMS_COMMAND: + return en50221_app_lowspeed_parse_command(lowspeed, + slot_id, + session_number, + data + 3, + data_length - 3); + case TAG_COMMS_SEND_LAST: + return en50221_app_lowspeed_parse_send(lowspeed, slot_id, + session_number, 1, + data + 3, + data_length - 3); + case TAG_COMMS_SEND_MORE: + return en50221_app_lowspeed_parse_send(lowspeed, slot_id, + session_number, 0, + data + 3, + data_length - 3); + } + + print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); + return -1; } static int en50221_app_lowspeed_parse_connect_on_channel(struct en50221_app_lowspeed_command *command, - uint8_t *data, - int data_length) + uint8_t *data, + int data_length) { - if (data_length < 3) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - - // check the tag - uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; - if (tag != TAG_CONNECTION_DESCRIPTOR) { - print(LOG_LEVEL, ERROR, 1, "Received bad CONNECT_ON_CHANNEL\n"); - return -1; - } - data+=3; - data_length-=3; - - // parse the descriptor-length-field - uint16_t asn_data_length; - int length_field_len; - if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { - print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); - return -1; - } - data+=length_field_len; - data_length-=length_field_len; - - // check length field - if (asn_data_length > data_length) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - if (asn_data_length < 1) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - - // get the descriptor type - command->u.connect_on_channel.descriptor_type = data[0]; - data++; - data_length--; - asn_data_length--; - - // deal with the descriptor itself - switch(command->u.connect_on_channel.descriptor_type) { - case CONNECTION_DESCRIPTOR_TYPE_TELEPHONE: - { - // get the raw descriptor and validate length - struct descriptor *d = (struct descriptor*) data; - if (asn_data_length < 2) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - if (asn_data_length != (2 + d->len)) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - if (d->tag != dtag_dvb_telephone) { - print(LOG_LEVEL, ERROR, 1, "Received invalid telephone descriptor\n"); - return -1; - } - - // parse the telephone descriptor - command->u.connect_on_channel.descriptor.telephone = dvb_telephone_descriptor_codec(d); - if (command->u.connect_on_channel.descriptor.telephone == NULL) { - print(LOG_LEVEL, ERROR, 1, "Received invalid telephone descriptor\n"); - return -1; - } - data += 2 + d->len; - data_length -= 2 + d->len; - break; - } - case CONNECTION_DESCRIPTOR_TYPE_CABLE: - if (asn_data_length != 1) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - command->u.connect_on_channel.descriptor.cable_channel_id = data[0]; - data++; - data_length--; - break; - default: - print(LOG_LEVEL, ERROR, 1, "Received unknown connection descriptor %02x\n", - command->u.connect_on_channel.descriptor_type); - return -1; - } - - // parse the last bit - if (data_length != 2) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - command->u.connect_on_channel.retry_count = data[0]; - command->u.connect_on_channel.timeout = data[1]; - - // ok - return 0; + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + // check the tag + uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; + if (tag != TAG_CONNECTION_DESCRIPTOR) { + print(LOG_LEVEL, ERROR, 1, + "Received bad CONNECT_ON_CHANNEL\n"); + return -1; + } + data += 3; + data_length -= 3; + + // parse the descriptor-length-field + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); + return -1; + } + data += length_field_len; + data_length -= length_field_len; + + // check length field + if (asn_data_length > data_length) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (asn_data_length < 1) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + // get the descriptor type + command->u.connect_on_channel.descriptor_type = data[0]; + data++; + data_length--; + asn_data_length--; + + // deal with the descriptor itself + switch (command->u.connect_on_channel.descriptor_type) { + case CONNECTION_DESCRIPTOR_TYPE_TELEPHONE: + { + // get the raw descriptor and validate length + struct descriptor *d = (struct descriptor *) data; + if (asn_data_length < 2) { + print(LOG_LEVEL, ERROR, 1, + "Received short data\n"); + return -1; + } + if (asn_data_length != (2 + d->len)) { + print(LOG_LEVEL, ERROR, 1, + "Received short data\n"); + return -1; + } + if (d->tag != dtag_dvb_telephone) { + print(LOG_LEVEL, ERROR, 1, + "Received invalid telephone descriptor\n"); + return -1; + } + // parse the telephone descriptor + command->u.connect_on_channel.descriptor.telephone = dvb_telephone_descriptor_codec(d); + if (command->u.connect_on_channel.descriptor.telephone == NULL) { + print(LOG_LEVEL, ERROR, 1, + "Received invalid telephone descriptor\n"); + return -1; + } + data += 2 + d->len; + data_length -= 2 + d->len; + break; + } + + case CONNECTION_DESCRIPTOR_TYPE_CABLE: + if (asn_data_length != 1) { + print(LOG_LEVEL, ERROR, 1, + "Received short data\n"); + return -1; + } + command->u.connect_on_channel.descriptor.cable_channel_id = data[0]; + data++; + data_length--; + break; + default: + print(LOG_LEVEL, ERROR, 1, + "Received unknown connection descriptor %02x\n", + command->u.connect_on_channel.descriptor_type); + return -1; + } + + // parse the last bit + if (data_length != 2) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + command->u.connect_on_channel.retry_count = data[0]; + command->u.connect_on_channel.timeout = data[1]; + + // ok + return 0; } -static int en50221_app_lowspeed_parse_command(struct en50221_app_lowspeed_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length) +static int en50221_app_lowspeed_parse_command(struct en50221_app_lowspeed *lowspeed, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length) { - // first of all, decode the length field - uint16_t asn_data_length; - int length_field_len; - if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { - print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); - return -1; - } - - // check it - if (asn_data_length < 1) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - if (asn_data_length > (data_length-length_field_len)) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - data+=length_field_len; - - // get command id - uint8_t command_id = data[0]; - data++; - asn_data_length--; - - // parse the command - struct en50221_app_lowspeed_command command; - switch(command_id) { - case COMMS_COMMAND_ID_CONNECT_ON_CHANNEL: - if (en50221_app_lowspeed_parse_connect_on_channel(&command, data, asn_data_length)) { - return -1; - } - break; - case COMMS_COMMAND_ID_SET_PARAMS: - if (asn_data_length != 2) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - command.u.set_params.buffer_size = data[0]; - command.u.set_params.timeout = data[1]; - break; - case COMMS_COMMAND_ID_GET_NEXT_BUFFER: - if (asn_data_length != 1) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - command.u.get_next_buffer.phase_id = data[0]; - break; - - case COMMS_COMMAND_ID_DISCONNECT_ON_CHANNEL: - case COMMS_COMMAND_ID_ENQUIRE_STATUS: - break; - - default: - print(LOG_LEVEL, ERROR, 1, "Received unexpected command_id %02x\n", command_id); - return -1; - } - - // tell the app - pthread_mutex_lock(&private->lock); - en50221_app_lowspeed_command_callback cb = private->command_callback; - void *cb_arg = private->command_callback_arg; - pthread_mutex_unlock(&private->lock); - if (cb) { - return cb(cb_arg, slot_id, session_number, command_id, &command); - } - return 0; + // first of all, decode the length field + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); + return -1; + } + // check it + if (asn_data_length < 1) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (asn_data_length > (data_length - length_field_len)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + data += length_field_len; + + // get command id + uint8_t command_id = data[0]; + data++; + asn_data_length--; + + // parse the command + struct en50221_app_lowspeed_command command; + switch (command_id) { + case COMMS_COMMAND_ID_CONNECT_ON_CHANNEL: + if (en50221_app_lowspeed_parse_connect_on_channel + (&command, data, asn_data_length)) { + return -1; + } + break; + case COMMS_COMMAND_ID_SET_PARAMS: + if (asn_data_length != 2) { + print(LOG_LEVEL, ERROR, 1, + "Received short data\n"); + return -1; + } + command.u.set_params.buffer_size = data[0]; + command.u.set_params.timeout = data[1]; + break; + case COMMS_COMMAND_ID_GET_NEXT_BUFFER: + if (asn_data_length != 1) { + print(LOG_LEVEL, ERROR, 1, + "Received short data\n"); + return -1; + } + command.u.get_next_buffer.phase_id = data[0]; + break; + + case COMMS_COMMAND_ID_DISCONNECT_ON_CHANNEL: + case COMMS_COMMAND_ID_ENQUIRE_STATUS: + break; + + default: + print(LOG_LEVEL, ERROR, 1, + "Received unexpected command_id %02x\n", command_id); + return -1; + } + + // tell the app + pthread_mutex_lock(&lowspeed->lock); + en50221_app_lowspeed_command_callback cb = lowspeed->command_callback; + void *cb_arg = lowspeed->command_callback_arg; + pthread_mutex_unlock(&lowspeed->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, command_id, + &command); + } + return 0; } -static int en50221_app_lowspeed_parse_send(struct en50221_app_lowspeed_private *private, - uint8_t slot_id, uint16_t session_number, int more_last, - uint8_t *data, uint32_t data_length) +static int en50221_app_lowspeed_parse_send(struct en50221_app_lowspeed *lowspeed, + uint8_t slot_id, + uint16_t session_number, + int more_last, + uint8_t *data, + uint32_t data_length) { - // first of all, decode the length field - uint16_t asn_data_length; - int length_field_len; - if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { - print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); - return -1; - } - - // check it - if (asn_data_length > (data_length-length_field_len)) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - - // skip over the length field - data += length_field_len; - - // find previous session - pthread_mutex_lock(&private->lock); - struct en50221_app_lowspeed_session *cur_s = private->sessions; - while(cur_s) { - if (cur_s->session_number == session_number) - break; - cur_s=cur_s->next; - } - - // more data is still to come - if (!more_last) { - // if there was no previous session, create one - if (cur_s == NULL) { - cur_s = malloc(sizeof(struct en50221_app_lowspeed_session)); - if (cur_s == NULL) { - print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n"); - pthread_mutex_unlock(&private->lock); - return -1; - } - cur_s->session_number = session_number; - cur_s->block_chain = NULL; - cur_s->block_length = 0; - cur_s->next = private->sessions; - private->sessions = cur_s; - } - - // append the data - uint8_t *new_data = realloc(cur_s->block_chain, cur_s->block_length + asn_data_length); - if (new_data == NULL) { - print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n"); - pthread_mutex_unlock(&private->lock); - return -1; - } - memcpy(new_data + cur_s->block_length, data, asn_data_length); - cur_s->block_chain = new_data; - cur_s->block_length += asn_data_length; - - // done - pthread_mutex_unlock(&private->lock); - return 0; - } - - // we hit the last of a possible chain of fragments - int do_free = 0; - if (cur_s != NULL) { - // we have a preceding fragment - need to append - uint8_t *new_data = realloc(cur_s->block_chain, cur_s->block_length + asn_data_length); - if (new_data == NULL) { - print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n"); - pthread_mutex_unlock(&private->lock); - return -1; - } - memcpy(new_data + cur_s->block_length, data, asn_data_length); - asn_data_length = cur_s->block_length + asn_data_length; - data = new_data; - cur_s->block_chain = NULL; - cur_s->block_length = 0; - do_free = 1; - } - - // check the reassembled data length - if (asn_data_length < 1) { - pthread_mutex_unlock(&private->lock); - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - if (do_free) free(data); - return -1; - } - - // now, parse the data - uint8_t phase_id = data[0]; - - // tell the app - en50221_app_lowspeed_send_callback cb = private->send_callback; - void *cb_arg = private->send_callback_arg; - pthread_mutex_unlock(&private->lock); - int cbstatus = 0; - if (cb) { - cbstatus = cb(cb_arg, slot_id, session_number, phase_id, data+1, asn_data_length-1); - } - - // done - if (do_free) free(data); - return cbstatus; + // first of all, decode the length field + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); + return -1; + } + // check it + if (asn_data_length > (data_length - length_field_len)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + // skip over the length field + data += length_field_len; + + // find previous session + pthread_mutex_lock(&lowspeed->lock); + struct en50221_app_lowspeed_session *cur_s = lowspeed->sessions; + while (cur_s) { + if (cur_s->session_number == session_number) + break; + cur_s = cur_s->next; + } + + // more data is still to come + if (!more_last) { + // if there was no previous session, create one + if (cur_s == NULL) { + cur_s = malloc(sizeof(struct en50221_app_lowspeed_session)); + if (cur_s == NULL) { + print(LOG_LEVEL, ERROR, 1, + "Ran out of memory\n"); + pthread_mutex_unlock(&lowspeed->lock); + return -1; + } + cur_s->session_number = session_number; + cur_s->block_chain = NULL; + cur_s->block_length = 0; + cur_s->next = lowspeed->sessions; + lowspeed->sessions = cur_s; + } + // append the data + uint8_t *new_data = realloc(cur_s->block_chain, + cur_s->block_length + asn_data_length); + if (new_data == NULL) { + print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n"); + pthread_mutex_unlock(&lowspeed->lock); + return -1; + } + memcpy(new_data + cur_s->block_length, data, asn_data_length); + cur_s->block_chain = new_data; + cur_s->block_length += asn_data_length; + + // done + pthread_mutex_unlock(&lowspeed->lock); + return 0; + } + // we hit the last of a possible chain of fragments + int do_free = 0; + if (cur_s != NULL) { + // we have a preceding fragment - need to append + uint8_t *new_data = realloc(cur_s->block_chain, + cur_s->block_length + asn_data_length); + if (new_data == NULL) { + print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n"); + pthread_mutex_unlock(&lowspeed->lock); + return -1; + } + memcpy(new_data + cur_s->block_length, data, asn_data_length); + asn_data_length = cur_s->block_length + asn_data_length; + data = new_data; + cur_s->block_chain = NULL; + cur_s->block_length = 0; + do_free = 1; + } + // check the reassembled data length + if (asn_data_length < 1) { + pthread_mutex_unlock(&lowspeed->lock); + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + if (do_free) + free(data); + return -1; + } + // now, parse the data + uint8_t phase_id = data[0]; + + // tell the app + en50221_app_lowspeed_send_callback cb = lowspeed->send_callback; + void *cb_arg = lowspeed->send_callback_arg; + pthread_mutex_unlock(&lowspeed->lock); + int cbstatus = 0; + if (cb) { + cbstatus = + cb(cb_arg, slot_id, session_number, phase_id, data + 1, asn_data_length - 1); + } + // done + if (do_free) + free(data); + return cbstatus; } diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_lowspeed.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_lowspeed.h index 4a3e554..0ef983c 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_lowspeed.h +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_lowspeed.h @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,15 +18,14 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __EN50221_APPLICATION_LOWSPEED_H__ #define __EN50221_APPLICATION_LOWSPEED_H__ #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif #include <stdlib.h> @@ -57,26 +56,26 @@ extern "C" * Structure holding information on a received comms command. */ struct en50221_app_lowspeed_command { - union { - struct { - uint8_t descriptor_type; // CONNECTION_DESCRIPTOR_TYPE_* - uint8_t retry_count; - uint8_t timeout; - union { - struct dvb_telephone_descriptor *telephone; - uint8_t cable_channel_id; - } descriptor; - } connect_on_channel; - - struct { - uint8_t buffer_size; - uint8_t timeout; - } set_params; - - struct { - uint8_t phase_id; - } get_next_buffer; - } u; + union { + struct { + uint8_t descriptor_type; // CONNECTION_DESCRIPTOR_TYPE_* + uint8_t retry_count; + uint8_t timeout; + union { + struct dvb_telephone_descriptor *telephone; + uint8_t cable_channel_id; + } descriptor; + } connect_on_channel; + + struct { + uint8_t buffer_size; + uint8_t timeout; + } set_params; + + struct { + uint8_t phase_id; + } get_next_buffer; + } u; }; /** @@ -89,9 +88,11 @@ struct en50221_app_lowspeed_command { * @param command Pointer to a lowspeed command structure containing the command data. * @return 0 on success, -1 on failure. */ -typedef int (*en50221_app_lowspeed_command_callback)(void *arg, uint8_t slot_id, uint16_t session_number, - uint8_t command_id, - struct en50221_app_lowspeed_command *command); +typedef int (*en50221_app_lowspeed_command_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number, + uint8_t command_id, + struct en50221_app_lowspeed_command *command); /** * Type definition for send - called when we receive data to send. The block can be segmented into @@ -105,13 +106,17 @@ typedef int (*en50221_app_lowspeed_command_callback)(void *arg, uint8_t slot_id, * @param length Number of bytes. * @return 0 on success, -1 on failure. */ -typedef int (*en50221_app_lowspeed_send_callback)(void *arg, uint8_t slot_id, uint16_t session_number, - uint8_t phase_id, uint8_t *data, uint32_t length); +typedef int (*en50221_app_lowspeed_send_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number, + uint8_t phase_id, + uint8_t *data, + uint32_t length); /** * Opaque type representing a lowspeed resource. */ -typedef void *en50221_app_lowspeed; +struct en50221_app_lowspeed; /** * Create an instance of the lowspeed resource. @@ -119,14 +124,15 @@ typedef void *en50221_app_lowspeed; * @param funcs Send functions to use. * @return Instance, or NULL on failure. */ -extern en50221_app_lowspeed en50221_app_lowspeed_create(struct en50221_app_send_functions *funcs); +extern struct en50221_app_lowspeed * + en50221_app_lowspeed_create(struct en50221_app_send_functions *funcs); /** * Destroy an instance of the lowspeed resource. * * @param lowspeed Instance to destroy. */ -extern void en50221_app_lowspeed_destroy(en50221_app_lowspeed lowspeed); +extern void en50221_app_lowspeed_destroy(struct en50221_app_lowspeed *lowspeed); /** * Informs the lowspeed object that a session to it has been closed - cleans up internal state. @@ -134,7 +140,8 @@ extern void en50221_app_lowspeed_destroy(en50221_app_lowspeed lowspeed); * @param lowspeed lowspeed resource instance. * @param session_number The session concerned. */ -extern void en50221_app_lowspeed_clear_session(en50221_app_lowspeed lowspeed, uint16_t session_number); +extern void en50221_app_lowspeed_clear_session(struct en50221_app_lowspeed *lowspeed, + uint16_t session_number); /** * Register the callback for when we receive a comms command. @@ -143,8 +150,9 @@ extern void en50221_app_lowspeed_clear_session(en50221_app_lowspeed lowspeed, ui * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_app_lowspeed_register_command_callback(en50221_app_lowspeed lowspeed, - en50221_app_lowspeed_command_callback callback, void *arg); +extern void en50221_app_lowspeed_register_command_callback(struct en50221_app_lowspeed *lowspeed, + en50221_app_lowspeed_command_callback callback, + void *arg); /** * Register the callback for when we receive data to send. @@ -153,8 +161,9 @@ extern void en50221_app_lowspeed_register_command_callback(en50221_app_lowspeed * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_app_lowspeed_register_send_callback(en50221_app_lowspeed lowspeed, - en50221_app_lowspeed_send_callback callback, void *arg); +extern void en50221_app_lowspeed_register_send_callback(struct en50221_app_lowspeed *lowspeed, + en50221_app_lowspeed_send_callback callback, + void *arg); /** * Send a comms reply to the CAM. @@ -165,10 +174,10 @@ extern void en50221_app_lowspeed_register_send_callback(en50221_app_lowspeed low * @param return_value Comms reply specific value. * @return 0 on success, -1 on failure. */ -extern int en50221_app_lowspeed_send_comms_reply(en50221_app_lowspeed lowspeed, - uint16_t session_number, - uint8_t comms_reply_id, - uint8_t return_value); +extern int en50221_app_lowspeed_send_comms_reply(struct en50221_app_lowspeed *lowspeed, + uint16_t session_number, + uint8_t comms_reply_id, + uint8_t return_value); /** * Send received data to the CAM. @@ -180,11 +189,11 @@ extern int en50221_app_lowspeed_send_comms_reply(en50221_app_lowspeed lowspeed, * @param tx_data Data. * @return 0 on success, -1 on failure. */ -extern int en50221_app_lowspeed_send_comms_data(en50221_app_lowspeed lowspeed, - uint16_t session_number, - uint8_t phase_id, - uint32_t tx_data_length, - uint8_t *tx_data); +extern int en50221_app_lowspeed_send_comms_data(struct en50221_app_lowspeed *lowspeed, + uint16_t session_number, + uint8_t phase_id, + uint32_t tx_data_length, + uint8_t * tx_data); /** * Pass data received for this resource into it for parsing. @@ -197,14 +206,14 @@ extern int en50221_app_lowspeed_send_comms_data(en50221_app_lowspeed lowspeed, * @param data_length Length of data in bytes. * @return 0 on success, -1 on failure. */ -extern int en50221_app_lowspeed_message(en50221_app_lowspeed lowspeed, - uint8_t slot_id, - uint16_t session_number, - uint32_t resource_id, - uint8_t *data, uint32_t data_length); +extern int en50221_app_lowspeed_message(struct en50221_app_lowspeed *lowspeed, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t * data, + uint32_t data_length); #ifdef __cplusplus } #endif - #endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_mmi.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_mmi.c index bb82678..830eaa3 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_mmi.c +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_mmi.c @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,7 +18,7 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <string.h> @@ -30,1287 +30,1368 @@ #include "asn_1.h" struct en50221_app_mmi_session { - uint16_t session_number; + uint16_t session_number; - uint8_t *menu_block_chain; - uint32_t menu_block_length; + uint8_t *menu_block_chain; + uint32_t menu_block_length; - uint8_t *list_block_chain; - uint32_t list_block_length; + uint8_t *list_block_chain; + uint32_t list_block_length; - uint8_t *subtitlesegment_block_chain; - uint32_t subtitlesegment_block_length; + uint8_t *subtitlesegment_block_chain; + uint32_t subtitlesegment_block_length; - uint8_t *subtitledownload_block_chain; - uint32_t subtitledownload_block_length; + uint8_t *subtitledownload_block_chain; + uint32_t subtitledownload_block_length; - struct en50221_app_mmi_session *next; + struct en50221_app_mmi_session *next; }; -struct en50221_app_mmi_private { - struct en50221_app_send_functions *funcs; - struct en50221_app_mmi_session *sessions; +struct en50221_app_mmi { + struct en50221_app_send_functions *funcs; + struct en50221_app_mmi_session *sessions; - en50221_app_mmi_close_callback closecallback; - void *closecallback_arg; + en50221_app_mmi_close_callback closecallback; + void *closecallback_arg; - en50221_app_mmi_display_control_callback displaycontrolcallback; - void *displaycontrolcallback_arg; + en50221_app_mmi_display_control_callback displaycontrolcallback; + void *displaycontrolcallback_arg; - en50221_app_mmi_keypad_control_callback keypadcontrolcallback; - void *keypadcontrolcallback_arg; + en50221_app_mmi_keypad_control_callback keypadcontrolcallback; + void *keypadcontrolcallback_arg; - en50221_app_mmi_subtitle_segment_callback subtitlesegmentcallback; - void *subtitlesegmentcallback_arg; + en50221_app_mmi_subtitle_segment_callback subtitlesegmentcallback; + void *subtitlesegmentcallback_arg; - en50221_app_mmi_scene_end_mark_callback sceneendmarkcallback; - void *sceneendmarkcallback_arg; + en50221_app_mmi_scene_end_mark_callback sceneendmarkcallback; + void *sceneendmarkcallback_arg; - en50221_app_mmi_scene_control_callback scenecontrolcallback; - void *scenecontrolcallback_arg; + en50221_app_mmi_scene_control_callback scenecontrolcallback; + void *scenecontrolcallback_arg; - en50221_app_mmi_subtitle_download_callback subtitledownloadcallback; - void *subtitledownloadcallback_arg; + en50221_app_mmi_subtitle_download_callback subtitledownloadcallback; + void *subtitledownloadcallback_arg; - en50221_app_mmi_flush_download_callback flushdownloadcallback; - void *flushdownloadcallback_arg; + en50221_app_mmi_flush_download_callback flushdownloadcallback; + void *flushdownloadcallback_arg; - en50221_app_mmi_enq_callback enqcallback; - void *enqcallback_arg; + en50221_app_mmi_enq_callback enqcallback; + void *enqcallback_arg; - en50221_app_mmi_menu_callback menucallback; - void *menucallback_arg; + en50221_app_mmi_menu_callback menucallback; + void *menucallback_arg; - en50221_app_mmi_list_callback listcallback; - void *listcallback_arg; + en50221_app_mmi_list_callback listcallback; + void *listcallback_arg; - pthread_mutex_t lock; + pthread_mutex_t lock; }; -static int en50221_app_mmi_parse_close(struct en50221_app_mmi_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length); -static int en50221_app_mmi_parse_display_control(struct en50221_app_mmi_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length); -static int en50221_app_mmi_parse_keypad_control(struct en50221_app_mmi_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length); -static int en50221_app_mmi_parse_enq(struct en50221_app_mmi_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length); -static int en50221_app_mmi_parse_list_menu(struct en50221_app_mmi_private *private, - uint8_t slot_id, uint16_t session_number, uint32_t tag_id, - int more_last, uint8_t *data, uint32_t data_length); -static int en50221_app_mmi_parse_subtitle(struct en50221_app_mmi_private *private, - uint8_t slot_id, uint16_t session_number, uint32_t tag_id, - int more_last, uint8_t *data, uint32_t data_length); -static int en50221_app_mmi_parse_scene_end_mark(struct en50221_app_mmi_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length); -static int en50221_app_mmi_parse_scene_control(struct en50221_app_mmi_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length); -static int en50221_app_mmi_parse_subtitle(struct en50221_app_mmi_private *private, - uint8_t slot_id, uint16_t session_number, uint32_t tag_id, - int more_last, uint8_t *data, uint32_t data_length); -static int en50221_app_mmi_parse_flush_download(struct en50221_app_mmi_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length); -static int en50221_app_mmi_defragment(struct en50221_app_mmi_private *private, - uint16_t session_number, - uint32_t tag_id, - int more_last, - uint8_t *indata, - uint32_t indata_length, - uint8_t **outdata, - uint32_t *outdata_length); -static int en50221_app_mmi_defragment_text(uint8_t *data, - uint32_t data_length, - uint8_t **outdata, - uint32_t *outdata_length, - uint32_t *outconsumed); - - - -en50221_app_mmi en50221_app_mmi_create(struct en50221_app_send_functions *funcs) +static int en50221_app_mmi_parse_close(struct en50221_app_mmi *mmi, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length); +static int en50221_app_mmi_parse_display_control(struct en50221_app_mmi + *mmi, uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length); +static int en50221_app_mmi_parse_keypad_control(struct en50221_app_mmi + *mmi, uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length); +static int en50221_app_mmi_parse_enq(struct en50221_app_mmi *mmi, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, uint32_t data_length); +static int en50221_app_mmi_parse_list_menu(struct en50221_app_mmi *mmi, + uint8_t slot_id, + uint16_t session_number, + uint32_t tag_id, int more_last, + uint8_t * data, + uint32_t data_length); +static int en50221_app_mmi_parse_subtitle(struct en50221_app_mmi *mmi, + uint8_t slot_id, + uint16_t session_number, + uint32_t tag_id, int more_last, + uint8_t * data, + uint32_t data_length); +static int en50221_app_mmi_parse_scene_end_mark(struct en50221_app_mmi *mmi, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length); +static int en50221_app_mmi_parse_scene_control(struct en50221_app_mmi *mmi, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length); +static int en50221_app_mmi_parse_subtitle(struct en50221_app_mmi *mmi, + uint8_t slot_id, + uint16_t session_number, + uint32_t tag_id, int more_last, + uint8_t * data, + uint32_t data_length); +static int en50221_app_mmi_parse_flush_download(struct en50221_app_mmi *mmi, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length); +static int en50221_app_mmi_defragment(struct en50221_app_mmi *mmi, + uint16_t session_number, + uint32_t tag_id, int more_last, + uint8_t * indata, + uint32_t indata_length, + uint8_t ** outdata, + uint32_t * outdata_length); +static int en50221_app_mmi_defragment_text(uint8_t * data, + uint32_t data_length, + uint8_t ** outdata, + uint32_t * outdata_length, + uint32_t * outconsumed); + + + +struct en50221_app_mmi *en50221_app_mmi_create(struct en50221_app_send_functions *funcs) { - struct en50221_app_mmi_private *private = NULL; - - // create structure and set it up - private = malloc(sizeof(struct en50221_app_mmi_private)); - if (private == NULL) { - return NULL; - } - private->funcs = funcs; - private->closecallback = NULL; - private->displaycontrolcallback = NULL; - private->keypadcontrolcallback = NULL; - private->subtitlesegmentcallback = NULL; - private->sceneendmarkcallback = NULL; - private->scenecontrolcallback = NULL; - private->subtitledownloadcallback = NULL; - private->flushdownloadcallback = NULL; - private->enqcallback = NULL; - private->menucallback = NULL; - private->listcallback = NULL; - private->sessions = NULL; - - pthread_mutex_init(&private->lock, NULL); - - // done - return private; + struct en50221_app_mmi *mmi = NULL; + + // create structure and set it up + mmi = malloc(sizeof(struct en50221_app_mmi)); + if (mmi == NULL) { + return NULL; + } + mmi->funcs = funcs; + mmi->closecallback = NULL; + mmi->displaycontrolcallback = NULL; + mmi->keypadcontrolcallback = NULL; + mmi->subtitlesegmentcallback = NULL; + mmi->sceneendmarkcallback = NULL; + mmi->scenecontrolcallback = NULL; + mmi->subtitledownloadcallback = NULL; + mmi->flushdownloadcallback = NULL; + mmi->enqcallback = NULL; + mmi->menucallback = NULL; + mmi->listcallback = NULL; + mmi->sessions = NULL; + + pthread_mutex_init(&mmi->lock, NULL); + + // done + return mmi; } -void en50221_app_mmi_destroy(en50221_app_mmi mmi) +void en50221_app_mmi_destroy(struct en50221_app_mmi *mmi) { - struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; - - struct en50221_app_mmi_session *cur_s = private->sessions; - while(cur_s) { - struct en50221_app_mmi_session *next = cur_s->next; - if (cur_s->menu_block_chain) - free(cur_s->menu_block_chain); - if (cur_s->list_block_chain) - free(cur_s->list_block_chain); - if (cur_s->subtitlesegment_block_chain) - free(cur_s->subtitlesegment_block_chain); - if (cur_s->subtitledownload_block_chain) - free(cur_s->subtitledownload_block_chain); - free(cur_s); - cur_s = next; - } - - pthread_mutex_destroy(&private->lock); - free(private); + struct en50221_app_mmi_session *cur_s = mmi->sessions; + while (cur_s) { + struct en50221_app_mmi_session *next = cur_s->next; + if (cur_s->menu_block_chain) + free(cur_s->menu_block_chain); + if (cur_s->list_block_chain) + free(cur_s->list_block_chain); + if (cur_s->subtitlesegment_block_chain) + free(cur_s->subtitlesegment_block_chain); + if (cur_s->subtitledownload_block_chain) + free(cur_s->subtitledownload_block_chain); + free(cur_s); + cur_s = next; + } + + pthread_mutex_destroy(&mmi->lock); + free(mmi); } -void en50221_app_mmi_clear_session(en50221_app_mmi mmi, uint16_t session_number) +void en50221_app_mmi_clear_session(struct en50221_app_mmi *mmi, + uint16_t session_number) { - struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; - - pthread_mutex_lock(&private->lock); - struct en50221_app_mmi_session *cur_s = private->sessions; - struct en50221_app_mmi_session *prev_s = NULL; - while(cur_s) { - if (cur_s->session_number == session_number) { - if (cur_s->menu_block_chain) - free(cur_s->menu_block_chain); - if (cur_s->list_block_chain) - free(cur_s->list_block_chain); - if (cur_s->subtitlesegment_block_chain) - free(cur_s->subtitlesegment_block_chain); - if (cur_s->subtitledownload_block_chain) - free(cur_s->subtitledownload_block_chain); - if (prev_s) { - prev_s->next = cur_s->next; - } else { - private->sessions = cur_s->next; - } - free(cur_s); - return; - } - - prev_s = cur_s; - cur_s=cur_s->next; - } - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&mmi->lock); + struct en50221_app_mmi_session *cur_s = mmi->sessions; + struct en50221_app_mmi_session *prev_s = NULL; + while (cur_s) { + if (cur_s->session_number == session_number) { + if (cur_s->menu_block_chain) + free(cur_s->menu_block_chain); + if (cur_s->list_block_chain) + free(cur_s->list_block_chain); + if (cur_s->subtitlesegment_block_chain) + free(cur_s->subtitlesegment_block_chain); + if (cur_s->subtitledownload_block_chain) + free(cur_s->subtitledownload_block_chain); + if (prev_s) { + prev_s->next = cur_s->next; + } else { + mmi->sessions = cur_s->next; + } + free(cur_s); + return; + } + + prev_s = cur_s; + cur_s = cur_s->next; + } + pthread_mutex_unlock(&mmi->lock); } -void en50221_app_mmi_register_close_callback(en50221_app_mmi mmi, - en50221_app_mmi_close_callback callback, void *arg) +void en50221_app_mmi_register_close_callback(struct en50221_app_mmi *mmi, + en50221_app_mmi_close_callback callback, + void *arg) { - struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; - - pthread_mutex_lock(&private->lock); - private->closecallback = callback; - private->closecallback_arg = arg; - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&mmi->lock); + mmi->closecallback = callback; + mmi->closecallback_arg = arg; + pthread_mutex_unlock(&mmi->lock); } -void en50221_app_mmi_register_display_control_callback(en50221_app_mmi mmi, - en50221_app_mmi_display_control_callback callback, void *arg) +void en50221_app_mmi_register_display_control_callback(struct en50221_app_mmi *mmi, + en50221_app_mmi_display_control_callback callback, + void *arg) { - struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; - - pthread_mutex_lock(&private->lock); - private->displaycontrolcallback = callback; - private->displaycontrolcallback_arg = arg; - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&mmi->lock); + mmi->displaycontrolcallback = callback; + mmi->displaycontrolcallback_arg = arg; + pthread_mutex_unlock(&mmi->lock); } -void en50221_app_mmi_register_keypad_control_callback(en50221_app_mmi mmi, - en50221_app_mmi_keypad_control_callback callback, void *arg) +void en50221_app_mmi_register_keypad_control_callback(struct en50221_app_mmi *mmi, + en50221_app_mmi_keypad_control_callback callback, + void *arg) { - struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; - - pthread_mutex_lock(&private->lock); - private->keypadcontrolcallback = callback; - private->keypadcontrolcallback_arg = arg; - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&mmi->lock); + mmi->keypadcontrolcallback = callback; + mmi->keypadcontrolcallback_arg = arg; + pthread_mutex_unlock(&mmi->lock); } -void en50221_app_mmi_register_subtitle_segment_callback(en50221_app_mmi mmi, - en50221_app_mmi_subtitle_segment_callback callback, void *arg) +void en50221_app_mmi_register_subtitle_segment_callback(struct en50221_app_mmi *mmi, + en50221_app_mmi_subtitle_segment_callback callback, + void *arg) { - struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; - - pthread_mutex_lock(&private->lock); - private->subtitlesegmentcallback = callback; - private->subtitlesegmentcallback_arg = arg; - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&mmi->lock); + mmi->subtitlesegmentcallback = callback; + mmi->subtitlesegmentcallback_arg = arg; + pthread_mutex_unlock(&mmi->lock); } -void en50221_app_mmi_register_scene_end_mark_callback(en50221_app_mmi mmi, - en50221_app_mmi_scene_end_mark_callback callback, void *arg) +void en50221_app_mmi_register_scene_end_mark_callback(struct en50221_app_mmi *mmi, + en50221_app_mmi_scene_end_mark_callback callback, void *arg) { - struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; - - pthread_mutex_lock(&private->lock); - private->sceneendmarkcallback = callback; - private->sceneendmarkcallback_arg = arg; - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&mmi->lock); + mmi->sceneendmarkcallback = callback; + mmi->sceneendmarkcallback_arg = arg; + pthread_mutex_unlock(&mmi->lock); } -void en50221_app_mmi_register_scene_control_callback(en50221_app_mmi mmi, - en50221_app_mmi_scene_control_callback callback, void *arg) +void en50221_app_mmi_register_scene_control_callback(struct en50221_app_mmi *mmi, + en50221_app_mmi_scene_control_callback callback, void *arg) { - struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; - - pthread_mutex_lock(&private->lock); - private->scenecontrolcallback = callback; - private->scenecontrolcallback_arg = arg; - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&mmi->lock); + mmi->scenecontrolcallback = callback; + mmi->scenecontrolcallback_arg = arg; + pthread_mutex_unlock(&mmi->lock); } -void en50221_app_mmi_register_subtitle_download_callback(en50221_app_mmi mmi, - en50221_app_mmi_subtitle_download_callback callback, void *arg) +void en50221_app_mmi_register_subtitle_download_callback(struct en50221_app_mmi *mmi, + en50221_app_mmi_subtitle_download_callback callback, + void *arg) { - struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; - - pthread_mutex_lock(&private->lock); - private->subtitledownloadcallback = callback; - private->subtitledownloadcallback_arg = arg; - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&mmi->lock); + mmi->subtitledownloadcallback = callback; + mmi->subtitledownloadcallback_arg = arg; + pthread_mutex_unlock(&mmi->lock); } -void en50221_app_mmi_register_flush_download_callback(en50221_app_mmi mmi, - en50221_app_mmi_flush_download_callback callback, void *arg) +void en50221_app_mmi_register_flush_download_callback(struct en50221_app_mmi *mmi, + en50221_app_mmi_flush_download_callback callback, + void *arg) { - struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; - - pthread_mutex_lock(&private->lock); - private->flushdownloadcallback = callback; - private->flushdownloadcallback_arg = arg; - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&mmi->lock); + mmi->flushdownloadcallback = callback; + mmi->flushdownloadcallback_arg = arg; + pthread_mutex_unlock(&mmi->lock); } -void en50221_app_mmi_register_enq_callback(en50221_app_mmi mmi, - en50221_app_mmi_enq_callback callback, void *arg) +void en50221_app_mmi_register_enq_callback(struct en50221_app_mmi *mmi, + en50221_app_mmi_enq_callback callback, + void *arg) { - struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; - - pthread_mutex_lock(&private->lock); - private->enqcallback = callback; - private->enqcallback_arg = arg; - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&mmi->lock); + mmi->enqcallback = callback; + mmi->enqcallback_arg = arg; + pthread_mutex_unlock(&mmi->lock); } -void en50221_app_mmi_register_menu_callback(en50221_app_mmi mmi, - en50221_app_mmi_menu_callback callback, void *arg) +void en50221_app_mmi_register_menu_callback(struct en50221_app_mmi *mmi, + en50221_app_mmi_menu_callback callback, + void *arg) { - struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; - - pthread_mutex_lock(&private->lock); - private->menucallback = callback; - private->menucallback_arg = arg; - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&mmi->lock); + mmi->menucallback = callback; + mmi->menucallback_arg = arg; + pthread_mutex_unlock(&mmi->lock); } -void en50221_app_mmi_register_list_callback(en50221_app_mmi mmi, - en50221_app_mmi_list_callback callback, void *arg) +void en50221_app_mmi_register_list_callback(struct en50221_app_mmi *mmi, + en50221_app_mmi_list_callback callback, + void *arg) { - struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; - - pthread_mutex_lock(&private->lock); - private->listcallback = callback; - private->listcallback_arg = arg; - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&mmi->lock); + mmi->listcallback = callback; + mmi->listcallback_arg = arg; + pthread_mutex_unlock(&mmi->lock); } -int en50221_app_mmi_close(en50221_app_mmi mmi, - uint16_t session_number, - uint8_t cmd_id, - uint8_t delay) +int en50221_app_mmi_close(struct en50221_app_mmi *mmi, + uint16_t session_number, + uint8_t cmd_id, uint8_t delay) { - struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; - uint8_t data[6]; - int data_length = 5; - - data[0] = (TAG_CLOSE_MMI >> 16) & 0xFF; - data[1] = (TAG_CLOSE_MMI >> 8) & 0xFF; - data[2] = TAG_CLOSE_MMI & 0xFF; - data[3] = 1; - data[4] = cmd_id; - if (cmd_id == MMI_CLOSE_MMI_CMD_ID_DELAY) { - data[3] = 2; - data[5] = delay; - data_length = 6; - } - return private->funcs->send_data(private->funcs->arg, session_number, data, data_length); + uint8_t data[6]; + int data_length = 5; + + data[0] = (TAG_CLOSE_MMI >> 16) & 0xFF; + data[1] = (TAG_CLOSE_MMI >> 8) & 0xFF; + data[2] = TAG_CLOSE_MMI & 0xFF; + data[3] = 1; + data[4] = cmd_id; + if (cmd_id == MMI_CLOSE_MMI_CMD_ID_DELAY) { + data[3] = 2; + data[5] = delay; + data_length = 6; + } + return mmi->funcs->send_data(mmi->funcs->arg, session_number, data, + data_length); } -int en50221_app_mmi_display_reply(en50221_app_mmi mmi, - uint16_t session_number, - uint8_t reply_id, - struct en502221_app_mmi_display_reply_details *details) +int en50221_app_mmi_display_reply(struct en50221_app_mmi *mmi, + uint16_t session_number, + uint8_t reply_id, + struct en50221_app_mmi_display_reply_details *details) { - struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; - uint8_t data[32]; - struct iovec iov[2]; - uint32_t iov_count; - int length_field_len; - - // fill out the start of the header - data[0] = (TAG_DISPLAY_REPLY >> 16) & 0xFF; - data[1] = (TAG_DISPLAY_REPLY >> 8) & 0xFF; - data[2] = TAG_DISPLAY_REPLY & 0xFF; - - switch(reply_id) { - case MMI_DISPLAY_REPLY_ID_MMI_MODE_ACK: - data[3] = 2; - data[4] = reply_id; - data[5] = details->u.mode_ack.mmi_mode; - iov[0].iov_base = data; - iov[0].iov_len = 6; - iov_count = 1; - break; - - case MMI_DISPLAY_REPLY_ID_LIST_DISPLAY_CHAR_TABLES: - case MMI_DISPLAY_REPLY_ID_LIST_INPUT_CHAR_TABLES: - if ((length_field_len = asn_1_encode(details->u.char_table.table_length+1, data+3, 3)) < 0) { - return -1; - } - data[3+length_field_len] = reply_id; - iov[0].iov_base = data; - iov[0].iov_len = 3+length_field_len+1; - iov[1].iov_base = details->u.char_table.table; - iov[1].iov_len = details->u.char_table.table_length; - iov_count = 2; - break; - - case MMI_DISPLAY_REPLY_ID_LIST_OVERLAY_GFX_CHARACTERISTICS: - case MMI_DISPLAY_REPLY_ID_LIST_FULLSCREEN_GFX_CHARACTERISTICS: - { - if ((length_field_len = asn_1_encode(1+9+(details->u.gfx.num_pixel_depths*2), data+3, 3)) < 0) { - return -1; - } - data[3+length_field_len] = reply_id; - data[3+length_field_len+1] = details->u.gfx.width >> 8; - data[3+length_field_len+2] = details->u.gfx.width; - data[3+length_field_len+3] = details->u.gfx.height >> 8; - data[3+length_field_len+4] = details->u.gfx.height; - data[3+length_field_len+5] = ((details->u.gfx.aspect_ratio & 0x0f) << 4) | - ((details->u.gfx.gfx_relation_to_video & 0x07) << 1) | - (details->u.gfx.multiple_depths & 1); - data[3+length_field_len+6] = details->u.gfx.display_bytes >> 4; - data[3+length_field_len+7] = ((details->u.gfx.display_bytes & 0x0f) << 4) | - ((details->u.gfx.composition_buffer_bytes & 0xf0) >> 4); - data[3+length_field_len+8] = ((details->u.gfx.composition_buffer_bytes & 0x0f) << 4) | - ((details->u.gfx.object_cache_bytes & 0xf0) >> 4); - data[3+length_field_len+9] = ((details->u.gfx.object_cache_bytes & 0x0f) << 4) | - (details->u.gfx.num_pixel_depths & 0x0f); - - // render the pixel depths themselves - uint8_t *pixdepths = alloca(details->u.gfx.num_pixel_depths * 2); - if (pixdepths == NULL) { - return -1; - } - uint32_t i; - for(i=0; i < details->u.gfx.num_pixel_depths; i++) { - pixdepths[0] = ((details->u.gfx.pixel_depths[i].display_depth & 0x07) << 5) | - ((details->u.gfx.pixel_depths[i].pixels_per_byte & 0x07) << 2); - pixdepths[1] = details->u.gfx.pixel_depths[i].region_overhead; - pixdepths+=2; - } - - // make up the iovs - iov[0].iov_base = data; - iov[0].iov_len = 3+length_field_len+10; - iov[1].iov_base = pixdepths; - iov[1].iov_len = details->u.gfx.num_pixel_depths *2; - iov_count = 2; - break; - } - - default: - data[3] = 1; - data[4] = reply_id; - iov[0].iov_base = data; - iov[0].iov_len = 5; - iov_count = 1; - break; - } - - // sendit - return private->funcs->send_datav(private->funcs->arg, session_number, iov, iov_count); + uint8_t data[32]; + struct iovec iov[2]; + uint32_t iov_count; + int length_field_len; + + // fill out the start of the header + data[0] = (TAG_DISPLAY_REPLY >> 16) & 0xFF; + data[1] = (TAG_DISPLAY_REPLY >> 8) & 0xFF; + data[2] = TAG_DISPLAY_REPLY & 0xFF; + + switch (reply_id) { + case MMI_DISPLAY_REPLY_ID_MMI_MODE_ACK: + data[3] = 2; + data[4] = reply_id; + data[5] = details->u.mode_ack.mmi_mode; + iov[0].iov_base = data; + iov[0].iov_len = 6; + iov_count = 1; + break; + + case MMI_DISPLAY_REPLY_ID_LIST_DISPLAY_CHAR_TABLES: + case MMI_DISPLAY_REPLY_ID_LIST_INPUT_CHAR_TABLES: + if ((length_field_len = + asn_1_encode(details->u.char_table.table_length + 1, data + 3, 3)) < 0) { + return -1; + } + data[3 + length_field_len] = reply_id; + iov[0].iov_base = data; + iov[0].iov_len = 3 + length_field_len + 1; + iov[1].iov_base = details->u.char_table.table; + iov[1].iov_len = details->u.char_table.table_length; + iov_count = 2; + break; + + case MMI_DISPLAY_REPLY_ID_LIST_OVERLAY_GFX_CHARACTERISTICS: + case MMI_DISPLAY_REPLY_ID_LIST_FULLSCREEN_GFX_CHARACTERISTICS: + { + if ((length_field_len = + asn_1_encode(1 + 9 + (details->u.gfx.num_pixel_depths * 2), data + 3, 3)) < 0) { + return -1; + } + data[3 + length_field_len] = reply_id; + data[3 + length_field_len + 1] = details->u.gfx.width >> 8; + data[3 + length_field_len + 2] = details->u.gfx.width; + data[3 + length_field_len + 3] = details->u.gfx.height >> 8; + data[3 + length_field_len + 4] = details->u.gfx.height; + data[3 + length_field_len + 5] = + ((details->u.gfx.aspect_ratio & 0x0f) << 4) | + ((details->u.gfx.gfx_relation_to_video & 0x07) << 1) | + (details->u.gfx.multiple_depths & 1); + data[3 + length_field_len + 6] = details->u.gfx.display_bytes >> 4; + data[3 + length_field_len + 7] = + ((details->u.gfx.display_bytes & 0x0f) << 4) | + ((details->u.gfx.composition_buffer_bytes & 0xf0) >> 4); + data[3 + length_field_len + 8] = + ((details->u.gfx.composition_buffer_bytes & 0x0f) << 4) | + ((details->u.gfx.object_cache_bytes & 0xf0) >> 4); + data[3 + length_field_len + 9] = + ((details->u.gfx.object_cache_bytes & 0x0f) << 4) | + (details->u.gfx.num_pixel_depths & 0x0f); + + // render the pixel depths themselves + uint8_t *pixdepths = + alloca(details->u.gfx.num_pixel_depths * 2); + if (pixdepths == NULL) { + return -1; + } + uint32_t i; + for (i = 0; i < details->u.gfx.num_pixel_depths; i++) { + pixdepths[0] = + ((details->u.gfx.pixel_depths[i].display_depth & 0x07) << 5) | + ((details->u.gfx.pixel_depths[i].pixels_per_byte & 0x07) << 2); + pixdepths[1] = + details->u.gfx.pixel_depths[i].region_overhead; + pixdepths += 2; + } + + // make up the iovs + iov[0].iov_base = data; + iov[0].iov_len = 3 + length_field_len + 10; + iov[1].iov_base = pixdepths; + iov[1].iov_len = + details->u.gfx.num_pixel_depths * 2; + iov_count = 2; + break; + } + + default: + data[3] = 1; + data[4] = reply_id; + iov[0].iov_base = data; + iov[0].iov_len = 5; + iov_count = 1; + break; + } + + // sendit + return mmi->funcs->send_datav(mmi->funcs->arg, session_number, iov, iov_count); } -int en50221_app_mmi_keypress(en50221_app_mmi mmi, - uint16_t session_number, - uint8_t keycode) +int en50221_app_mmi_keypress(struct en50221_app_mmi *mmi, + uint16_t session_number, uint8_t keycode) { - struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; - uint8_t data[5]; - - data[0] = (TAG_KEYPRESS >> 16) & 0xFF; - data[1] = (TAG_KEYPRESS >> 8) & 0xFF; - data[2] = TAG_KEYPRESS & 0xFF; - data[3] = 1; - data[4] = keycode; - return private->funcs->send_data(private->funcs->arg, session_number, data, 5); + uint8_t data[5]; + + data[0] = (TAG_KEYPRESS >> 16) & 0xFF; + data[1] = (TAG_KEYPRESS >> 8) & 0xFF; + data[2] = TAG_KEYPRESS & 0xFF; + data[3] = 1; + data[4] = keycode; + return mmi->funcs->send_data(mmi->funcs->arg, session_number, data, 5); } -int en50221_app_mmi_display_message(en50221_app_mmi mmi, - uint16_t session_number, - uint8_t display_message_id) +int en50221_app_mmi_display_message(struct en50221_app_mmi *mmi, + uint16_t session_number, + uint8_t display_message_id) { - struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; - uint8_t data[5]; - - data[0] = (TAG_DISPLAY_MESSAGE >> 16) & 0xFF; - data[1] = (TAG_DISPLAY_MESSAGE >> 8) & 0xFF; - data[2] = TAG_DISPLAY_MESSAGE & 0xFF; - data[3] = 1; - data[4] = display_message_id; - return private->funcs->send_data(private->funcs->arg, session_number, data, 5); + uint8_t data[5]; + + data[0] = (TAG_DISPLAY_MESSAGE >> 16) & 0xFF; + data[1] = (TAG_DISPLAY_MESSAGE >> 8) & 0xFF; + data[2] = TAG_DISPLAY_MESSAGE & 0xFF; + data[3] = 1; + data[4] = display_message_id; + return mmi->funcs->send_data(mmi->funcs->arg, session_number, data, 5); } -int en50221_app_mmi_scene_done(en50221_app_mmi mmi, - uint16_t session_number, - uint8_t decoder_continue, - uint8_t scene_reveal, - uint8_t scene_tag) +int en50221_app_mmi_scene_done(struct en50221_app_mmi *mmi, + uint16_t session_number, + uint8_t decoder_continue, + uint8_t scene_reveal, uint8_t scene_tag) { - struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; - uint8_t data[5]; - - data[0] = (TAG_SCENE_DONE >> 16) & 0xFF; - data[1] = (TAG_SCENE_DONE >> 8) & 0xFF; - data[2] = TAG_SCENE_DONE & 0xFF; - data[3] = 1; - data[4] = (decoder_continue ? 0x80 : 0x00) | - (scene_reveal ? 0x40 : 0x00) | - (scene_tag & 0x0f); - return private->funcs->send_data(private->funcs->arg, session_number, data, 5); + uint8_t data[5]; + + data[0] = (TAG_SCENE_DONE >> 16) & 0xFF; + data[1] = (TAG_SCENE_DONE >> 8) & 0xFF; + data[2] = TAG_SCENE_DONE & 0xFF; + data[3] = 1; + data[4] = + (decoder_continue ? 0x80 : 0x00) | + (scene_reveal ? 0x40 : 0x00) | + (scene_tag & 0x0f); + return mmi->funcs->send_data(mmi->funcs->arg, session_number, data, 5); } -int en50221_app_mmi_download_reply(en50221_app_mmi mmi, - uint16_t session_number, - uint16_t object_id, - uint8_t download_reply_id) +int en50221_app_mmi_download_reply(struct en50221_app_mmi *mmi, + uint16_t session_number, + uint16_t object_id, + uint8_t download_reply_id) { - struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; - uint8_t data[7]; - - data[0] = (TAG_DOWNLOAD_REPLY >> 16) & 0xFF; - data[1] = (TAG_DOWNLOAD_REPLY >> 8) & 0xFF; - data[2] = TAG_DOWNLOAD_REPLY & 0xFF; - data[3] = 3; - data[4] = object_id >> 8; - data[5] = object_id; - data[6] = download_reply_id; - return private->funcs->send_data(private->funcs->arg, session_number, data, 7); + uint8_t data[7]; + + data[0] = (TAG_DOWNLOAD_REPLY >> 16) & 0xFF; + data[1] = (TAG_DOWNLOAD_REPLY >> 8) & 0xFF; + data[2] = TAG_DOWNLOAD_REPLY & 0xFF; + data[3] = 3; + data[4] = object_id >> 8; + data[5] = object_id; + data[6] = download_reply_id; + return mmi->funcs->send_data(mmi->funcs->arg, session_number, data, 7); } -int en50221_app_mmi_answ(en50221_app_mmi mmi, - uint16_t session_number, - uint8_t answ_id, - uint8_t *text, - uint32_t text_count) +int en50221_app_mmi_answ(struct en50221_app_mmi *mmi, + uint16_t session_number, + uint8_t answ_id, + uint8_t * text, uint32_t text_count) { - struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; - uint8_t buf[10]; - - // set up the tag - buf[0] = (TAG_ANSWER >> 16) & 0xFF; - buf[1] = (TAG_ANSWER >> 8) & 0xFF; - buf[2] = TAG_ANSWER & 0xFF; - - // encode the length field - struct iovec iov[2]; - int length_field_len = 0; - int iov_count = 1; - if (answ_id == MMI_ANSW_ID_ANSWER) { - if ((length_field_len = asn_1_encode(text_count+1, buf+3, 3)) < 0) { - return -1; - } - buf[3+length_field_len] = answ_id; - - iov[0].iov_base = buf; - iov[0].iov_len = 3+length_field_len+1; - iov[1].iov_base = text; - iov[1].iov_len = text_count; - iov_count=2; - } else { - buf[3] = 1; - buf[4] = answ_id; - iov[0].iov_base = buf; - iov[0].iov_len = 5; - iov_count = 1; - } - - // create the data and send it - return private->funcs->send_datav(private->funcs->arg, session_number, iov, iov_count); + uint8_t buf[10]; + + // set up the tag + buf[0] = (TAG_ANSWER >> 16) & 0xFF; + buf[1] = (TAG_ANSWER >> 8) & 0xFF; + buf[2] = TAG_ANSWER & 0xFF; + + // encode the length field + struct iovec iov[2]; + int length_field_len = 0; + int iov_count = 1; + if (answ_id == MMI_ANSW_ID_ANSWER) { + if ((length_field_len = asn_1_encode(text_count + 1, buf + 3, 3)) < 0) { + return -1; + } + buf[3 + length_field_len] = answ_id; + + iov[0].iov_base = buf; + iov[0].iov_len = 3 + length_field_len + 1; + iov[1].iov_base = text; + iov[1].iov_len = text_count; + iov_count = 2; + } else { + buf[3] = 1; + buf[4] = answ_id; + iov[0].iov_base = buf; + iov[0].iov_len = 5; + iov_count = 1; + } + + // create the data and send it + return mmi->funcs->send_datav(mmi->funcs->arg, session_number, iov, + iov_count); } -int en50221_app_mmi_menu_answ(en50221_app_mmi mmi, - uint16_t session_number, - uint8_t choice_ref) +int en50221_app_mmi_menu_answ(struct en50221_app_mmi *mmi, + uint16_t session_number, uint8_t choice_ref) { - struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; - uint8_t data[5]; - - data[0] = (TAG_MENU_ANSWER >> 16) & 0xFF; - data[1] = (TAG_MENU_ANSWER >> 8) & 0xFF; - data[2] = TAG_MENU_ANSWER & 0xFF; - data[3] = 1; - data[4] = choice_ref; - return private->funcs->send_data(private->funcs->arg, session_number, data, 5); + uint8_t data[5]; + + data[0] = (TAG_MENU_ANSWER >> 16) & 0xFF; + data[1] = (TAG_MENU_ANSWER >> 8) & 0xFF; + data[2] = TAG_MENU_ANSWER & 0xFF; + data[3] = 1; + data[4] = choice_ref; + return mmi->funcs->send_data(mmi->funcs->arg, session_number, data, 5); } -int en50221_app_mmi_message(en50221_app_mmi mmi, - uint8_t slot_id, - uint16_t session_number, - uint32_t resource_id, - uint8_t *data, uint32_t data_length) +int en50221_app_mmi_message(struct en50221_app_mmi *mmi, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t * data, uint32_t data_length) { - struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi; - (void) resource_id; - - // get the tag - if (data_length < 3) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; - - switch(tag) - { - case TAG_CLOSE_MMI: - return en50221_app_mmi_parse_close(private, slot_id, session_number, data+3, data_length-3); - case TAG_DISPLAY_CONTROL: - return en50221_app_mmi_parse_display_control(private, slot_id, session_number, data+3, data_length-3); - case TAG_KEYPAD_CONTROL: - return en50221_app_mmi_parse_keypad_control(private, slot_id, session_number, data+3, data_length-3); - case TAG_ENQUIRY: - return en50221_app_mmi_parse_enq(private, slot_id, session_number, data+3, data_length-3); - case TAG_MENU_LAST: - return en50221_app_mmi_parse_list_menu(private, slot_id, session_number, tag, 1, data+3, data_length-3); - case TAG_MENU_MORE: - return en50221_app_mmi_parse_list_menu(private, slot_id, session_number, tag, 0, data+3, data_length-3); - case TAG_LIST_LAST: - return en50221_app_mmi_parse_list_menu(private, slot_id, session_number, tag, 1, data+3, data_length-3); - case TAG_LIST_MORE: - return en50221_app_mmi_parse_list_menu(private, slot_id, session_number, tag, 0, data+3, data_length-3); - case TAG_SUBTITLE_SEGMENT_LAST: - return en50221_app_mmi_parse_subtitle(private, slot_id, session_number, tag, 1, data+3, data_length-3); - case TAG_SUBTITLE_SEGMENT_MORE: - return en50221_app_mmi_parse_subtitle(private, slot_id, session_number, tag, 0, data+3, data_length-3); - case TAG_SCENE_END_MARK: - return en50221_app_mmi_parse_scene_end_mark(private, slot_id, session_number, data+3, data_length-3); - case TAG_SCENE_CONTROL: - return en50221_app_mmi_parse_scene_control(private, slot_id, session_number, data+3, data_length-3); - case TAG_SUBTITLE_DOWNLOAD_LAST: - return en50221_app_mmi_parse_subtitle(private, slot_id, session_number, tag, 1, data+3, data_length-3); - case TAG_SUBTITLE_DOWNLOAD_MORE: - return en50221_app_mmi_parse_subtitle(private, slot_id, session_number, tag, 0, data+3, data_length-3); - case TAG_FLUSH_DOWNLOAD: - return en50221_app_mmi_parse_flush_download(private, slot_id, session_number, data+3, data_length-3); - } - - print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); - return -1; + (void) resource_id; + + // get the tag + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; + + switch (tag) { + case TAG_CLOSE_MMI: + return en50221_app_mmi_parse_close(mmi, slot_id, + session_number, + data + 3, + data_length - 3); + case TAG_DISPLAY_CONTROL: + return en50221_app_mmi_parse_display_control(mmi, slot_id, + session_number, + data + 3, + data_length - 3); + case TAG_KEYPAD_CONTROL: + return en50221_app_mmi_parse_keypad_control(mmi, slot_id, + session_number, + data + 3, + data_length - 3); + case TAG_ENQUIRY: + return en50221_app_mmi_parse_enq(mmi, slot_id, + session_number, data + 3, + data_length - 3); + case TAG_MENU_LAST: + return en50221_app_mmi_parse_list_menu(mmi, slot_id, + session_number, tag, + 1, data + 3, + data_length - 3); + case TAG_MENU_MORE: + return en50221_app_mmi_parse_list_menu(mmi, slot_id, + session_number, tag, + 0, data + 3, + data_length - 3); + case TAG_LIST_LAST: + return en50221_app_mmi_parse_list_menu(mmi, slot_id, + session_number, tag, + 1, data + 3, + data_length - 3); + case TAG_LIST_MORE: + return en50221_app_mmi_parse_list_menu(mmi, slot_id, + session_number, tag, + 0, data + 3, + data_length - 3); + case TAG_SUBTITLE_SEGMENT_LAST: + return en50221_app_mmi_parse_subtitle(mmi, slot_id, + session_number, tag, + 1, data + 3, + data_length - 3); + case TAG_SUBTITLE_SEGMENT_MORE: + return en50221_app_mmi_parse_subtitle(mmi, slot_id, + session_number, tag, + 0, data + 3, + data_length - 3); + case TAG_SCENE_END_MARK: + return en50221_app_mmi_parse_scene_end_mark(mmi, slot_id, + session_number, + data + 3, + data_length - 3); + case TAG_SCENE_CONTROL: + return en50221_app_mmi_parse_scene_control(mmi, slot_id, + session_number, + data + 3, + data_length - 3); + case TAG_SUBTITLE_DOWNLOAD_LAST: + return en50221_app_mmi_parse_subtitle(mmi, slot_id, + session_number, tag, + 1, data + 3, + data_length - 3); + case TAG_SUBTITLE_DOWNLOAD_MORE: + return en50221_app_mmi_parse_subtitle(mmi, slot_id, + session_number, tag, + 0, data + 3, + data_length - 3); + case TAG_FLUSH_DOWNLOAD: + return en50221_app_mmi_parse_flush_download(mmi, slot_id, + session_number, + data + 3, + data_length - 3); + } + + print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); + return -1; } -static int en50221_app_mmi_parse_close(struct en50221_app_mmi_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length) +static int en50221_app_mmi_parse_close(struct en50221_app_mmi *mmi, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length) { - // validate data - if (data_length < 2) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - if (data[0] > (data_length-1)) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - uint8_t cmd_id = data[1]; - uint8_t delay = 0; - if (cmd_id == MMI_CLOSE_MMI_CMD_ID_DELAY) { - if (data[0] != 2) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - delay = data[2]; - } - - // tell the app - pthread_mutex_lock(&private->lock); - en50221_app_mmi_close_callback cb = private->closecallback; - void *cb_arg = private->closecallback_arg; - pthread_mutex_unlock(&private->lock); - if (cb) { - return cb(cb_arg, slot_id, session_number, cmd_id, delay); - } - return 0; + // validate data + if (data_length < 2) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (data[0] > (data_length - 1)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint8_t cmd_id = data[1]; + uint8_t delay = 0; + if (cmd_id == MMI_CLOSE_MMI_CMD_ID_DELAY) { + if (data[0] != 2) { + print(LOG_LEVEL, ERROR, 1, + "Received short data\n"); + return -1; + } + delay = data[2]; + } + // tell the app + pthread_mutex_lock(&mmi->lock); + en50221_app_mmi_close_callback cb = mmi->closecallback; + void *cb_arg = mmi->closecallback_arg; + pthread_mutex_unlock(&mmi->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, cmd_id, delay); + } + return 0; } -static int en50221_app_mmi_parse_display_control(struct en50221_app_mmi_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length) +static int en50221_app_mmi_parse_display_control(struct en50221_app_mmi *mmi, + uint8_t slot_id, + uint16_t session_number, + uint8_t *data, + uint32_t data_length) { - // validate data - if (data_length < 2) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - if (data[0] > (data_length-1)) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - uint8_t cmd_id = data[1]; - uint8_t mmi_mode = 0; - if (cmd_id == MMI_DISPLAY_CONTROL_CMD_ID_SET_MMI_MODE) { - if (data[0] != 2) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - mmi_mode = data[2]; - } - - // tell the app - pthread_mutex_lock(&private->lock); - en50221_app_mmi_display_control_callback cb = private->displaycontrolcallback; - void *cb_arg = private->displaycontrolcallback_arg; - pthread_mutex_unlock(&private->lock); - if (cb) { - return cb(cb_arg, slot_id, session_number, cmd_id, mmi_mode); - } - return 0; + // validate data + if (data_length < 2) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (data[0] > (data_length - 1)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint8_t cmd_id = data[1]; + uint8_t mmi_mode = 0; + if (cmd_id == MMI_DISPLAY_CONTROL_CMD_ID_SET_MMI_MODE) { + if (data[0] != 2) { + print(LOG_LEVEL, ERROR, 1, + "Received short data\n"); + return -1; + } + mmi_mode = data[2]; + } + // tell the app + pthread_mutex_lock(&mmi->lock); + en50221_app_mmi_display_control_callback cb = mmi->displaycontrolcallback; + void *cb_arg = mmi->displaycontrolcallback_arg; + pthread_mutex_unlock(&mmi->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, cmd_id, mmi_mode); + } + return 0; } -static int en50221_app_mmi_parse_keypad_control(struct en50221_app_mmi_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length) +static int en50221_app_mmi_parse_keypad_control(struct en50221_app_mmi *mmi, + uint8_t slot_id, + uint16_t session_number, + uint8_t *data, + uint32_t data_length) { - // first of all, decode the length field - uint16_t asn_data_length; - int length_field_len; - if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { - print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); - return -1; - } - - // check it - if (asn_data_length > (data_length-length_field_len)) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - if (asn_data_length < 1) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - - // skip over the length field - data += length_field_len; - - // extract the information - uint8_t cmd_id = data[0]; - uint8_t *keycodes = data+1; - - // tell the app - pthread_mutex_lock(&private->lock); - en50221_app_mmi_keypad_control_callback cb = private->keypadcontrolcallback; - void *cb_arg = private->keypadcontrolcallback_arg; - pthread_mutex_unlock(&private->lock); - if (cb) { - return cb(cb_arg, slot_id, session_number, cmd_id, keycodes, asn_data_length-1); - } - return 0; + // first of all, decode the length field + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); + return -1; + } + // check it + if (asn_data_length > (data_length - length_field_len)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (asn_data_length < 1) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + // skip over the length field + data += length_field_len; + + // extract the information + uint8_t cmd_id = data[0]; + uint8_t *keycodes = data + 1; + + // tell the app + pthread_mutex_lock(&mmi->lock); + en50221_app_mmi_keypad_control_callback cb = mmi->keypadcontrolcallback; + void *cb_arg = mmi->keypadcontrolcallback_arg; + pthread_mutex_unlock(&mmi->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, cmd_id, + keycodes, asn_data_length - 1); + } + return 0; } -static int en50221_app_mmi_parse_enq(struct en50221_app_mmi_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length) +static int en50221_app_mmi_parse_enq(struct en50221_app_mmi *mmi, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, uint32_t data_length) { - // first of all, decode the length field - uint16_t asn_data_length; - int length_field_len; - if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { - print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); - return -1; - } - - // check it - if (asn_data_length > (data_length-length_field_len)) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - if (asn_data_length < 2) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - - // skip over the length field - data += length_field_len; - - // extract the information - uint8_t blind_answer = (data[0] & 0x01) ? 1 : 0; - uint8_t answer_length = data[1]; - uint8_t *text = data+2; - - // tell the app - pthread_mutex_lock(&private->lock); - en50221_app_mmi_enq_callback cb = private->enqcallback; - void *cb_arg = private->enqcallback_arg; - pthread_mutex_unlock(&private->lock); - if (cb) { - return cb(cb_arg, slot_id, session_number, blind_answer, answer_length, text, asn_data_length - 2); - } - return 0; + // first of all, decode the length field + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); + return -1; + } + // check it + if (asn_data_length > (data_length - length_field_len)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (asn_data_length < 2) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + // skip over the length field + data += length_field_len; + + // extract the information + uint8_t blind_answer = (data[0] & 0x01) ? 1 : 0; + uint8_t answer_length = data[1]; + uint8_t *text = data + 2; + + // tell the app + pthread_mutex_lock(&mmi->lock); + en50221_app_mmi_enq_callback cb = mmi->enqcallback; + void *cb_arg = mmi->enqcallback_arg; + pthread_mutex_unlock(&mmi->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, blind_answer, + answer_length, text, asn_data_length - 2); + } + return 0; } -static int en50221_app_mmi_parse_list_menu(struct en50221_app_mmi_private *private, - uint8_t slot_id, uint16_t session_number, uint32_t tag_id, - int more_last, uint8_t *data, uint32_t data_length) +static int en50221_app_mmi_parse_list_menu(struct en50221_app_mmi *mmi, + uint8_t slot_id, + uint16_t session_number, + uint32_t tag_id, int more_last, + uint8_t * data, + uint32_t data_length) { - int result = 0; - uint8_t *text_flags = NULL; - struct en50221_app_mmi_text *text_data = NULL; - uint32_t i; - uint8_t text_count = 0; - - // first of all, decode the length field - uint16_t asn_data_length; - int length_field_len; - if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { - print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); - return -1; - } - - // check it - if (asn_data_length > (data_length-length_field_len)) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - - // skip over the length field - data += length_field_len; - - // defragment - pthread_mutex_lock(&private->lock); - uint8_t *outdata; - uint32_t outdata_length; - int dfstatus = en50221_app_mmi_defragment(private, session_number, tag_id, more_last, - data, asn_data_length, - &outdata, &outdata_length); - if (dfstatus <= 0) { - pthread_mutex_unlock(&private->lock); - return dfstatus; - } - data = outdata; - data_length = outdata_length; - - // check the reassembled data length - if (data_length < 1) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - pthread_mutex_unlock(&private->lock); - result = -1; - goto exit_cleanup; - } - - // now, parse the data - uint8_t choice_nb = data[0]; - text_count = choice_nb + 3; - if (choice_nb == 0xff) text_count = 3; - data++; - data_length--; - - // variables for extracted text state - text_flags = alloca(text_count); - if (text_flags == NULL) { - pthread_mutex_unlock(&private->lock); - result = -1; - goto exit_cleanup; - } - memset(text_flags, 0, text_count); - text_data = (struct en50221_app_mmi_text*) alloca(sizeof(struct en50221_app_mmi_text) * text_count); - if (text_data == NULL) { - pthread_mutex_unlock(&private->lock); - result = -1; - goto exit_cleanup; - } - memset(text_data, 0, sizeof(struct en50221_app_mmi_text) * text_count); - - // extract the text! - for(i=0; i<text_count; i++) { - uint32_t consumed = 0; - int cur_status = en50221_app_mmi_defragment_text(data, data_length, - &text_data[i].text, &text_data[i].text_length, - &consumed); - if (cur_status < 0) { - pthread_mutex_unlock(&private->lock); - result = -1; - goto exit_cleanup; - } - - text_flags[i] = cur_status; - data += consumed; - data_length -= consumed; - } - - // work out what to pass to the user - struct en50221_app_mmi_text *text_data_for_user = - (struct en50221_app_mmi_text*) alloca(sizeof(struct en50221_app_mmi_text) * text_count); - if (text_data_for_user == NULL) { - result = -1; - goto exit_cleanup; - } - memcpy(text_data_for_user, text_data, sizeof(struct en50221_app_mmi_text) * text_count); - struct en50221_app_mmi_text *text_ptr = NULL; - if (text_count > 3) { - text_ptr = &text_data_for_user[3]; - } - uint8_t *items_raw = NULL; - uint32_t items_raw_length = 0; - if (choice_nb == 0xff) { - items_raw = data; - items_raw_length = data_length; - } - - // do callback - result = 0; - switch(tag_id) { - case TAG_MENU_LAST: - { - en50221_app_mmi_menu_callback cb = private->menucallback; - void *cb_arg = private->menucallback_arg; - pthread_mutex_unlock(&private->lock); - if (cb) { - result = cb(cb_arg, slot_id, session_number, - &text_data_for_user[0], - &text_data_for_user[1], - &text_data_for_user[2], - text_count-3, - text_ptr, - items_raw_length, - items_raw); - } - break; - } - - case TAG_LIST_LAST: - { - en50221_app_mmi_list_callback cb = private->listcallback; - void *cb_arg = private->listcallback_arg; - pthread_mutex_unlock(&private->lock); - if (cb) { - result = cb(cb_arg, slot_id, session_number, - &text_data_for_user[0], - &text_data_for_user[1], - &text_data_for_user[2], - text_count-3, - text_ptr, - items_raw_length, - items_raw); - } - break; - } - - default: - pthread_mutex_unlock(&private->lock); - break; - } + int result = 0; + uint8_t *text_flags = NULL; + struct en50221_app_mmi_text *text_data = NULL; + uint32_t i; + uint8_t text_count = 0; + + // first of all, decode the length field + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); + return -1; + } + // check it + if (asn_data_length > (data_length - length_field_len)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + // skip over the length field + data += length_field_len; + + // defragment + pthread_mutex_lock(&mmi->lock); + uint8_t *outdata; + uint32_t outdata_length; + int dfstatus = + en50221_app_mmi_defragment(mmi, session_number, tag_id, + more_last, + data, asn_data_length, + &outdata, &outdata_length); + if (dfstatus <= 0) { + pthread_mutex_unlock(&mmi->lock); + return dfstatus; + } + data = outdata; + data_length = outdata_length; + + // check the reassembled data length + if (data_length < 1) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + pthread_mutex_unlock(&mmi->lock); + result = -1; + goto exit_cleanup; + } + // now, parse the data + uint8_t choice_nb = data[0]; + text_count = choice_nb + 3; + if (choice_nb == 0xff) + text_count = 3; + data++; + data_length--; + + // variables for extracted text state + text_flags = alloca(text_count); + if (text_flags == NULL) { + pthread_mutex_unlock(&mmi->lock); + result = -1; + goto exit_cleanup; + } + memset(text_flags, 0, text_count); + text_data = (struct en50221_app_mmi_text *) + alloca(sizeof(struct en50221_app_mmi_text) * text_count); + if (text_data == NULL) { + pthread_mutex_unlock(&mmi->lock); + result = -1; + goto exit_cleanup; + } + memset(text_data, 0, + sizeof(struct en50221_app_mmi_text) * text_count); + + // extract the text! + for (i = 0; i < text_count; i++) { + uint32_t consumed = 0; + int cur_status = + en50221_app_mmi_defragment_text(data, data_length, + &text_data[i].text, + &text_data[i].text_length, + &consumed); + if (cur_status < 0) { + pthread_mutex_unlock(&mmi->lock); + result = -1; + goto exit_cleanup; + } + + text_flags[i] = cur_status; + data += consumed; + data_length -= consumed; + } + + // work out what to pass to the user + struct en50221_app_mmi_text *text_data_for_user = (struct en50221_app_mmi_text *) + alloca(sizeof(struct en50221_app_mmi_text) * text_count); + if (text_data_for_user == NULL) { + result = -1; + goto exit_cleanup; + } + memcpy(text_data_for_user, text_data, + sizeof(struct en50221_app_mmi_text) * text_count); + struct en50221_app_mmi_text *text_ptr = NULL; + if (text_count > 3) { + text_ptr = &text_data_for_user[3]; + } + uint8_t *items_raw = NULL; + uint32_t items_raw_length = 0; + if (choice_nb == 0xff) { + items_raw = data; + items_raw_length = data_length; + } + // do callback + result = 0; + switch (tag_id) { + case TAG_MENU_LAST: + { + en50221_app_mmi_menu_callback cb = mmi->menucallback; + void *cb_arg = mmi->menucallback_arg; + pthread_mutex_unlock(&mmi->lock); + if (cb) { + result = + cb(cb_arg, slot_id, session_number, + &text_data_for_user[0], + &text_data_for_user[1], + &text_data_for_user[2], + text_count - 3, text_ptr, + items_raw_length, items_raw); + } + break; + } + + case TAG_LIST_LAST: + { + en50221_app_mmi_list_callback cb = mmi->listcallback; + void *cb_arg = mmi->listcallback_arg; + pthread_mutex_unlock(&mmi->lock); + if (cb) { + result = + cb(cb_arg, slot_id, session_number, + &text_data_for_user[0], + &text_data_for_user[1], + &text_data_for_user[2], + text_count - 3, text_ptr, + items_raw_length, items_raw); + } + break; + } + + default: + pthread_mutex_unlock(&mmi->lock); + break; + } exit_cleanup: - if ((dfstatus == 2) && outdata) free(outdata); - if (text_flags && text_data) { - for(i=0; i< text_count; i++) { - if ((text_flags[i] == 2) && text_data[i].text) { - free(text_data[i].text); - } - } - } - return result; + if ((dfstatus == 2) && outdata) + free(outdata); + if (text_flags && text_data) { + for (i = 0; i < text_count; i++) { + if ((text_flags[i] == 2) && text_data[i].text) { + free(text_data[i].text); + } + } + } + return result; } -static int en50221_app_mmi_parse_subtitle(struct en50221_app_mmi_private *private, - uint8_t slot_id, uint16_t session_number, uint32_t tag_id, - int more_last, uint8_t *data, uint32_t data_length) +static int en50221_app_mmi_parse_subtitle(struct en50221_app_mmi *mmi, + uint8_t slot_id, + uint16_t session_number, + uint32_t tag_id, int more_last, + uint8_t * data, + uint32_t data_length) { - // first of all, decode the length field - uint16_t asn_data_length; - int length_field_len; - if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { - print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); - return -1; - } - - // check it - if (asn_data_length > (data_length-length_field_len)) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - - // skip over the length field - data += length_field_len; - - // defragment - pthread_mutex_lock(&private->lock); - uint8_t *outdata; - uint32_t outdata_length; - int dfstatus = en50221_app_mmi_defragment(private, session_number, tag_id, more_last, - data, asn_data_length, - &outdata, &outdata_length); - if (dfstatus <= 0) { - pthread_mutex_unlock(&private->lock); - return dfstatus; - } - - // do callback - int cbstatus = 0; - switch(tag_id) { - case TAG_SUBTITLE_SEGMENT_LAST: - { - en50221_app_mmi_subtitle_segment_callback cb = private->subtitlesegmentcallback; - void *cb_arg = private->subtitlesegmentcallback_arg; - pthread_mutex_unlock(&private->lock); - if (cb) { - cbstatus = cb(cb_arg, slot_id, session_number, outdata, outdata_length); - } - break; - } - - case TAG_SUBTITLE_DOWNLOAD_LAST: - { - en50221_app_mmi_subtitle_download_callback cb = private->subtitledownloadcallback; - void *cb_arg = private->subtitledownloadcallback_arg; - pthread_mutex_unlock(&private->lock); - if (cb) { - cbstatus = cb(cb_arg, slot_id, session_number, outdata, outdata_length); - } - break; - } - } - - // free the data returned by the defragment call if asked to - if (dfstatus == 2) { - free(outdata); - } - - // done - return cbstatus; + // first of all, decode the length field + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); + return -1; + } + // check it + if (asn_data_length > (data_length - length_field_len)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + // skip over the length field + data += length_field_len; + + // defragment + pthread_mutex_lock(&mmi->lock); + uint8_t *outdata; + uint32_t outdata_length; + int dfstatus = + en50221_app_mmi_defragment(mmi, session_number, tag_id, + more_last, + data, asn_data_length, + &outdata, &outdata_length); + if (dfstatus <= 0) { + pthread_mutex_unlock(&mmi->lock); + return dfstatus; + } + // do callback + int cbstatus = 0; + switch (tag_id) { + case TAG_SUBTITLE_SEGMENT_LAST: + { + en50221_app_mmi_subtitle_segment_callback cb = + mmi->subtitlesegmentcallback; + void *cb_arg = mmi->subtitlesegmentcallback_arg; + pthread_mutex_unlock(&mmi->lock); + if (cb) { + cbstatus = + cb(cb_arg, slot_id, session_number, outdata, outdata_length); + } + break; + } + + case TAG_SUBTITLE_DOWNLOAD_LAST: + { + en50221_app_mmi_subtitle_download_callback cb = + mmi->subtitledownloadcallback; + void *cb_arg = mmi->subtitledownloadcallback_arg; + pthread_mutex_unlock(&mmi->lock); + if (cb) { + cbstatus = + cb(cb_arg, slot_id, session_number, outdata, outdata_length); + } + break; + } + } + + // free the data returned by the defragment call if asked to + if (dfstatus == 2) { + free(outdata); + } + // done + return cbstatus; } -static int en50221_app_mmi_parse_scene_end_mark(struct en50221_app_mmi_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length) +static int en50221_app_mmi_parse_scene_end_mark(struct en50221_app_mmi *mmi, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length) { - // validate data - if (data_length != 2) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - if (data[0] != 1) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - uint8_t flags = data[1]; - - // tell the app - pthread_mutex_lock(&private->lock); - en50221_app_mmi_scene_end_mark_callback cb = private->sceneendmarkcallback; - void *cb_arg = private->sceneendmarkcallback_arg; - pthread_mutex_unlock(&private->lock); - if (cb) { - return cb(cb_arg, slot_id, session_number, - (flags & 0x80) ? 1 : 0, - (flags & 0x40) ? 1 : 0, - (flags & 0x20) ? 1 : 0, - flags & 0x0f); - } - return 0; + // validate data + if (data_length != 2) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (data[0] != 1) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint8_t flags = data[1]; + + // tell the app + pthread_mutex_lock(&mmi->lock); + en50221_app_mmi_scene_end_mark_callback cb = + mmi->sceneendmarkcallback; + void *cb_arg = mmi->sceneendmarkcallback_arg; + pthread_mutex_unlock(&mmi->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, + (flags & 0x80) ? 1 : 0, + (flags & 0x40) ? 1 : 0, + (flags & 0x20) ? 1 : 0, flags & 0x0f); + } + return 0; } -static int en50221_app_mmi_parse_scene_control(struct en50221_app_mmi_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length) +static int en50221_app_mmi_parse_scene_control(struct en50221_app_mmi *mmi, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length) { - // validate data - if (data_length != 2) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - if (data[0] != 1) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - uint8_t flags = data[1]; - - // tell the app - pthread_mutex_lock(&private->lock); - en50221_app_mmi_scene_control_callback cb = private->scenecontrolcallback; - void *cb_arg = private->scenecontrolcallback_arg; - pthread_mutex_unlock(&private->lock); - if (cb) { - return cb(cb_arg, slot_id, session_number, - (flags & 0x80) ? 1 : 0, - (flags & 0x40) ? 1 : 0, - flags & 0x0f); - } - return 0; + // validate data + if (data_length != 2) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (data[0] != 1) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint8_t flags = data[1]; + + // tell the app + pthread_mutex_lock(&mmi->lock); + en50221_app_mmi_scene_control_callback cb = mmi->scenecontrolcallback; + void *cb_arg = mmi->scenecontrolcallback_arg; + pthread_mutex_unlock(&mmi->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, + (flags & 0x80) ? 1 : 0, + (flags & 0x40) ? 1 : 0, flags & 0x0f); + } + return 0; } -static int en50221_app_mmi_parse_flush_download(struct en50221_app_mmi_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length) +static int en50221_app_mmi_parse_flush_download(struct en50221_app_mmi *mmi, + uint8_t slot_id, + uint16_t session_number, + uint8_t *data, + uint32_t data_length) { - // validate data - if (data_length != 1) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - if (data[0] != 0) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - - // tell the app - pthread_mutex_lock(&private->lock); - en50221_app_mmi_flush_download_callback cb = private->flushdownloadcallback; - void *cb_arg = private->flushdownloadcallback_arg; - pthread_mutex_unlock(&private->lock); - if (cb) { - return cb(cb_arg, slot_id, session_number); - } - return 0; + // validate data + if (data_length != 1) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (data[0] != 0) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + // tell the app + pthread_mutex_lock(&mmi->lock); + en50221_app_mmi_flush_download_callback cb = mmi->flushdownloadcallback; + void *cb_arg = mmi->flushdownloadcallback_arg; + pthread_mutex_unlock(&mmi->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number); + } + return 0; } -static int en50221_app_mmi_defragment(struct en50221_app_mmi_private *private, - uint16_t session_number, - uint32_t tag_id, - int more_last, - uint8_t *indata, - uint32_t indata_length, - uint8_t **outdata, - uint32_t *outdata_length) +static int en50221_app_mmi_defragment(struct en50221_app_mmi *mmi, + uint16_t session_number, + uint32_t tag_id, + int more_last, + uint8_t * indata, + uint32_t indata_length, + uint8_t ** outdata, + uint32_t * outdata_length) { - struct en50221_app_mmi_session *cur_s = private->sessions; - while(cur_s) { - if (cur_s->session_number == session_number) - break; - cur_s=cur_s->next; - } - - // more data is still to come - if (!more_last) { - // if there was no previous session, create one - if (cur_s == NULL) { - cur_s = malloc(sizeof(struct en50221_app_mmi_session)); - if (cur_s == NULL) { - print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n"); - return -1; - } - cur_s->session_number = session_number; - cur_s->menu_block_chain = NULL; - cur_s->menu_block_length = 0; - cur_s->list_block_chain = NULL; - cur_s->list_block_length = 0; - cur_s->subtitlesegment_block_chain = NULL; - cur_s->subtitlesegment_block_length = 0; - cur_s->subtitledownload_block_chain = NULL; - cur_s->subtitledownload_block_length = 0; - cur_s->next = private->sessions; - private->sessions = cur_s; - } - - // find the block/block_length to use - uint8_t **block_chain; - uint32_t *block_length; - switch(tag_id) { - case TAG_MENU_LAST: - case TAG_MENU_MORE: - block_chain = &cur_s->menu_block_chain; - block_length = &cur_s->menu_block_length; - break; - case TAG_LIST_LAST: - case TAG_LIST_MORE: - block_chain = &cur_s->list_block_chain; - block_length = &cur_s->list_block_length; - break; - case TAG_SUBTITLE_SEGMENT_LAST: - case TAG_SUBTITLE_SEGMENT_MORE: - block_chain = &cur_s->subtitlesegment_block_chain; - block_length = &cur_s->subtitlesegment_block_length; - break; - case TAG_SUBTITLE_DOWNLOAD_LAST: - case TAG_SUBTITLE_DOWNLOAD_MORE: - block_chain = &cur_s->subtitledownload_block_chain; - block_length = &cur_s->subtitledownload_block_length; - break; - default: - return -1; - } - - // append the data - uint8_t *new_data = realloc(*block_chain, *block_length + indata_length); - if (new_data == NULL) { - print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n"); - return -1; - } - memcpy(new_data + *block_length, indata, indata_length); - *block_chain = new_data; - *block_length += indata_length; - - // success, but block not complete yet - return 0; - } - - // we hit the last of a possible chain of fragments - if (cur_s != NULL) { - // find the block/block_length to use - uint8_t **block_chain; - uint32_t *block_length; - switch(tag_id) { - case TAG_MENU_LAST: - case TAG_MENU_MORE: - block_chain = &cur_s->menu_block_chain; - block_length = &cur_s->menu_block_length; - break; - case TAG_LIST_LAST: - case TAG_LIST_MORE: - block_chain = &cur_s->list_block_chain; - block_length = &cur_s->list_block_length; - break; - case TAG_SUBTITLE_SEGMENT_LAST: - case TAG_SUBTITLE_SEGMENT_MORE: - block_chain = &cur_s->subtitlesegment_block_chain; - block_length = &cur_s->subtitlesegment_block_length; - break; - case TAG_SUBTITLE_DOWNLOAD_LAST: - case TAG_SUBTITLE_DOWNLOAD_MORE: - block_chain = &cur_s->subtitledownload_block_chain; - block_length = &cur_s->subtitledownload_block_length; - break; - default: - return -1; - } - - // we have a preceding fragment - need to append - uint8_t *new_data = realloc(*block_chain, *block_length + indata_length); - if (new_data == NULL) { - print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n"); - return -1; - } - memcpy(new_data + *block_length, indata, indata_length); - *outdata_length = *block_length + indata_length; - *outdata = new_data; - *block_chain = NULL; - *block_length = 0; - - // success, and indicate to free the block when done - return 2; - } - - // success, but indicate it is not to be freed - *outdata_length = indata_length; - *outdata = indata; - return 1; + struct en50221_app_mmi_session *cur_s = mmi->sessions; + while (cur_s) { + if (cur_s->session_number == session_number) + break; + cur_s = cur_s->next; + } + + // more data is still to come + if (!more_last) { + // if there was no previous session, create one + if (cur_s == NULL) { + cur_s = malloc(sizeof(struct en50221_app_mmi_session)); + if (cur_s == NULL) { + print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n"); + return -1; + } + cur_s->session_number = session_number; + cur_s->menu_block_chain = NULL; + cur_s->menu_block_length = 0; + cur_s->list_block_chain = NULL; + cur_s->list_block_length = 0; + cur_s->subtitlesegment_block_chain = NULL; + cur_s->subtitlesegment_block_length = 0; + cur_s->subtitledownload_block_chain = NULL; + cur_s->subtitledownload_block_length = 0; + cur_s->next = mmi->sessions; + mmi->sessions = cur_s; + } + // find the block/block_length to use + uint8_t **block_chain; + uint32_t *block_length; + switch (tag_id) { + case TAG_MENU_LAST: + case TAG_MENU_MORE: + block_chain = &cur_s->menu_block_chain; + block_length = &cur_s->menu_block_length; + break; + case TAG_LIST_LAST: + case TAG_LIST_MORE: + block_chain = &cur_s->list_block_chain; + block_length = &cur_s->list_block_length; + break; + case TAG_SUBTITLE_SEGMENT_LAST: + case TAG_SUBTITLE_SEGMENT_MORE: + block_chain = &cur_s->subtitlesegment_block_chain; + block_length = &cur_s->subtitlesegment_block_length; + break; + case TAG_SUBTITLE_DOWNLOAD_LAST: + case TAG_SUBTITLE_DOWNLOAD_MORE: + block_chain = &cur_s->subtitledownload_block_chain; + block_length = &cur_s->subtitledownload_block_length; + break; + default: + return -1; + } + + // append the data + uint8_t *new_data = + realloc(*block_chain, *block_length + indata_length); + if (new_data == NULL) { + print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n"); + return -1; + } + memcpy(new_data + *block_length, indata, indata_length); + *block_chain = new_data; + *block_length += indata_length; + + // success, but block not complete yet + return 0; + } + // we hit the last of a possible chain of fragments + if (cur_s != NULL) { + // find the block/block_length to use + uint8_t **block_chain; + uint32_t *block_length; + switch (tag_id) { + case TAG_MENU_LAST: + case TAG_MENU_MORE: + block_chain = &cur_s->menu_block_chain; + block_length = &cur_s->menu_block_length; + break; + case TAG_LIST_LAST: + case TAG_LIST_MORE: + block_chain = &cur_s->list_block_chain; + block_length = &cur_s->list_block_length; + break; + case TAG_SUBTITLE_SEGMENT_LAST: + case TAG_SUBTITLE_SEGMENT_MORE: + block_chain = &cur_s->subtitlesegment_block_chain; + block_length = &cur_s->subtitlesegment_block_length; + break; + case TAG_SUBTITLE_DOWNLOAD_LAST: + case TAG_SUBTITLE_DOWNLOAD_MORE: + block_chain = &cur_s->subtitledownload_block_chain; + block_length = &cur_s->subtitledownload_block_length; + break; + default: + return -1; + } + + // we have a preceding fragment - need to append + uint8_t *new_data = + realloc(*block_chain, *block_length + indata_length); + if (new_data == NULL) { + print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n"); + return -1; + } + memcpy(new_data + *block_length, indata, indata_length); + *outdata_length = *block_length + indata_length; + *outdata = new_data; + *block_chain = NULL; + *block_length = 0; + + // success, and indicate to free the block when done + return 2; + } + // success, but indicate it is not to be freed + *outdata_length = indata_length; + *outdata = indata; + return 1; } -static int en50221_app_mmi_defragment_text(uint8_t *data, - uint32_t data_length, - uint8_t **outdata, - uint32_t *outdata_length, - uint32_t *outconsumed) +static int en50221_app_mmi_defragment_text(uint8_t * data, + uint32_t data_length, + uint8_t ** outdata, + uint32_t * outdata_length, + uint32_t * outconsumed) { - uint8_t *text = NULL; - uint32_t text_length = 0; - uint32_t consumed = 0; - - while(1) { - // get the tag - if (data_length < 3) { - print(LOG_LEVEL, ERROR, 1, "Short data\n"); - if (text) free(text); - return -1; - } - uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; - data += 3; - data_length -=3; - consumed += 3; - - // get the length of the data and adjust - uint16_t asn_data_length; - int length_field_len; - if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { - print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); - if (text) free(text); - return -1; - } - data += length_field_len; - data_length -= length_field_len; - consumed += length_field_len; - - // deal with the tags - if (tag == TAG_TEXT_LAST) { - if (text == NULL) { - *outdata = data; - *outdata_length = asn_data_length; - *outconsumed = consumed + asn_data_length; - return 1; - } else { - // append the data - uint8_t *new_text = realloc(text, text_length + asn_data_length); - if (new_text == NULL) { - print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n"); - if (text) free(text); - return -1; - } - memcpy(new_text + text_length, data, asn_data_length); - *outdata = new_text; - *outdata_length = text_length + asn_data_length; - *outconsumed = consumed + asn_data_length; - return 2; - } - - } else if (tag == TAG_TEXT_MORE) { - // append the data - uint8_t *new_text = realloc(text, text_length + asn_data_length); - if (new_text == NULL) { - print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n"); - if (text) free(text); - return -1; - } - memcpy(new_text + text_length, data, asn_data_length); - text = new_text; - text_length += asn_data_length; - - // consume the data - data += asn_data_length; - data_length -= asn_data_length; - consumed += asn_data_length; - } else { - // unknown tag - print(LOG_LEVEL, ERROR, 1, "Unknown MMI text tag\n"); - if (text) free(text); - return -1; - } - } + uint8_t *text = NULL; + uint32_t text_length = 0; + uint32_t consumed = 0; + + while (1) { + // get the tag + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Short data\n"); + if (text) + free(text); + return -1; + } + uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; + data += 3; + data_length -= 3; + consumed += 3; + + // get the length of the data and adjust + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = + asn_1_decode(&asn_data_length, data, + data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); + if (text) + free(text); + return -1; + } + data += length_field_len; + data_length -= length_field_len; + consumed += length_field_len; + + // deal with the tags + if (tag == TAG_TEXT_LAST) { + if (text == NULL) { + *outdata = data; + *outdata_length = asn_data_length; + *outconsumed = consumed + asn_data_length; + return 1; + } else { + // append the data + uint8_t *new_text = realloc(text, + text_length + asn_data_length); + if (new_text == NULL) { + print(LOG_LEVEL, ERROR, 1, + "Ran out of memory\n"); + if (text) + free(text); + return -1; + } + memcpy(new_text + text_length, data, + asn_data_length); + *outdata = new_text; + *outdata_length = + text_length + asn_data_length; + *outconsumed = consumed + asn_data_length; + return 2; + } + + } else if (tag == TAG_TEXT_MORE) { + // append the data + uint8_t *new_text = + realloc(text, text_length + asn_data_length); + if (new_text == NULL) { + print(LOG_LEVEL, ERROR, 1, + "Ran out of memory\n"); + if (text) + free(text); + return -1; + } + memcpy(new_text + text_length, data, + asn_data_length); + text = new_text; + text_length += asn_data_length; + + // consume the data + data += asn_data_length; + data_length -= asn_data_length; + consumed += asn_data_length; + } else { + // unknown tag + print(LOG_LEVEL, ERROR, 1, + "Unknown MMI text tag\n"); + if (text) + free(text); + return -1; + } + } } diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_mmi.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_mmi.h index 486080f..5c5b727 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_mmi.h +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_mmi.h @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,15 +18,14 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __EN50221_APPLICATION_mmi_H__ #define __EN50221_APPLICATION_mmi_H__ #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif #include <stdlib.h> @@ -88,48 +87,48 @@ extern "C" * A pixel depth as supplied with display_reply details */ struct en50221_app_mmi_pixel_depth { - uint8_t display_depth; - uint8_t pixels_per_byte; - uint8_t region_overhead; + uint8_t display_depth; + uint8_t pixels_per_byte; + uint8_t region_overhead; }; /** * Details returned with a display_reply */ -struct en502221_app_mmi_display_reply_details { - union { - struct { - uint16_t width; - uint16_t height; - uint8_t aspect_ratio; - uint8_t gfx_relation_to_video; /* one of MMI_GFX_VIDEO_RELATION_* */ - uint8_t multiple_depths; - uint16_t display_bytes; - uint8_t composition_buffer_bytes; - uint8_t object_cache_bytes; - uint8_t num_pixel_depths; - struct en50221_app_mmi_pixel_depth *pixel_depths; - } gfx; /* MMI_DISPLAY_REPLY_ID_LIST_OVERLAY_GFX_CHARACTERISTICS or - MMI_DISPLAY_REPLY_ID_LIST_FULLSCREEN_GFX_CHARACTERISTICS */ - - struct { - uint32_t table_length; - uint8_t *table; - } char_table; /* MMI_DISPLAY_REPLY_ID_LIST_DISPLAY_CHAR_TABLES or - MMI_DISPLAY_REPLY_ID_LIST_INPUT_CHAR_TABLES */ - - struct { - uint8_t mmi_mode; /* one of the MMI_MODE_* values */ - } mode_ack; /* for MMI_DISPLAY_REPLY_ID_MMI_MODE_ACK */ - } u; +struct en50221_app_mmi_display_reply_details { + union { + struct { + uint16_t width; + uint16_t height; + uint8_t aspect_ratio; + uint8_t gfx_relation_to_video; /* one of MMI_GFX_VIDEO_RELATION_* */ + uint8_t multiple_depths; + uint16_t display_bytes; + uint8_t composition_buffer_bytes; + uint8_t object_cache_bytes; + uint8_t num_pixel_depths; + struct en50221_app_mmi_pixel_depth *pixel_depths; + } gfx; /* MMI_DISPLAY_REPLY_ID_LIST_OVERLAY_GFX_CHARACTERISTICS or + MMI_DISPLAY_REPLY_ID_LIST_FULLSCREEN_GFX_CHARACTERISTICS */ + + struct { + uint32_t table_length; + uint8_t *table; + } char_table; /* MMI_DISPLAY_REPLY_ID_LIST_DISPLAY_CHAR_TABLES or + MMI_DISPLAY_REPLY_ID_LIST_INPUT_CHAR_TABLES */ + + struct { + uint8_t mmi_mode; /* one of the MMI_MODE_* values */ + } mode_ack; /* for MMI_DISPLAY_REPLY_ID_MMI_MODE_ACK */ + } u; }; /** * Pointer to a text string. */ struct en50221_app_mmi_text { - uint8_t *text; - uint32_t text_length; + uint8_t *text; + uint32_t text_length; }; /** @@ -142,8 +141,11 @@ struct en50221_app_mmi_text { * @param delay Delay supplied with MMI_CLOSE_MMI_CMD_ID_DELAY. * @return 0 on success, -1 on failure. */ -typedef int (*en50221_app_mmi_close_callback)(void *arg, uint8_t slot_id, uint16_t session_number, - uint8_t cmd_id, uint8_t delay); +typedef int (*en50221_app_mmi_close_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number, + uint8_t cmd_id, + uint8_t delay); /** * Type definition for display_control callback. @@ -155,8 +157,11 @@ typedef int (*en50221_app_mmi_close_callback)(void *arg, uint8_t slot_id, uint16 * @param delay One of the MMI_MODE_* values. * @return 0 on success, -1 on failure. */ -typedef int (*en50221_app_mmi_display_control_callback)(void *arg, uint8_t slot_id, uint16_t session_number, - uint8_t cmd_id, uint8_t mmi_mode); +typedef int (*en50221_app_mmi_display_control_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number, + uint8_t cmd_id, + uint8_t mmi_mode); /** * Type definition for keypad_control callback. @@ -169,8 +174,12 @@ typedef int (*en50221_app_mmi_display_control_callback)(void *arg, uint8_t slot_ * @param key_codes_count Number of key codes. * @return 0 on success, -1 on failure. */ -typedef int (*en50221_app_mmi_keypad_control_callback)(void *arg, uint8_t slot_id, uint16_t session_number, - uint8_t cmd_id, uint8_t *key_codes, uint32_t key_codes_count); +typedef int (*en50221_app_mmi_keypad_control_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number, + uint8_t cmd_id, + uint8_t *key_codes, + uint32_t key_codes_count); /** * Type definition for subtitle_segment callback. @@ -182,8 +191,11 @@ typedef int (*en50221_app_mmi_keypad_control_callback)(void *arg, uint8_t slot_i * @param segment_size Size of segment data. * @return 0 on success, -1 on failure. */ -typedef int (*en50221_app_mmi_subtitle_segment_callback)(void *arg, uint8_t slot_id, uint16_t session_number, - uint8_t *segment, uint32_t segment_size); +typedef int (*en50221_app_mmi_subtitle_segment_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number, + uint8_t *segment, + uint32_t segment_size); /** * Type definition for scene_end_mark callback. @@ -197,9 +209,13 @@ typedef int (*en50221_app_mmi_subtitle_segment_callback)(void *arg, uint8_t slot * @param scene_tag * @return 0 on success, -1 on failure. */ -typedef int (*en50221_app_mmi_scene_end_mark_callback)(void *arg, uint8_t slot_id, uint16_t session_number, - uint8_t decoder_continue_flag, uint8_t scene_reveal_flag, - uint8_t send_scene_done, uint8_t scene_tag); +typedef int (*en50221_app_mmi_scene_end_mark_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number, + uint8_t decoder_continue_flag, + uint8_t scene_reveal_flag, + uint8_t send_scene_done, + uint8_t scene_tag); /** * Type definition for scene_control callback. @@ -212,9 +228,12 @@ typedef int (*en50221_app_mmi_scene_end_mark_callback)(void *arg, uint8_t slot_i * @param scene_tag * @return 0 on success, -1 on failure. */ -typedef int (*en50221_app_mmi_scene_control_callback)(void *arg, uint8_t slot_id, uint16_t session_number, - uint8_t decoder_continue_flag, uint8_t scene_reveal_flag, - uint8_t scene_tag); +typedef int (*en50221_app_mmi_scene_control_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number, + uint8_t decoder_continue_flag, + uint8_t scene_reveal_flag, + uint8_t scene_tag); /** * Type definition for subtitle_download callback. @@ -226,8 +245,11 @@ typedef int (*en50221_app_mmi_scene_control_callback)(void *arg, uint8_t slot_id * @param segment_size Size of segment data. * @return 0 on success, -1 on failure. */ -typedef int (*en50221_app_mmi_subtitle_download_callback)(void *arg, uint8_t slot_id, uint16_t session_number, - uint8_t *segment, uint32_t segment_size); +typedef int (*en50221_app_mmi_subtitle_download_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number, + uint8_t *segment, + uint32_t segment_size); /** * Type definition for flush_download callback. @@ -237,7 +259,9 @@ typedef int (*en50221_app_mmi_subtitle_download_callback)(void *arg, uint8_t slo * @param session_number Session number concerned. * @return 0 on success, -1 on failure. */ -typedef int (*en50221_app_mmi_flush_download_callback)(void *arg, uint8_t slot_id, uint16_t session_number); +typedef int (*en50221_app_mmi_flush_download_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number); /** * Type definition for enq callback. @@ -251,9 +275,13 @@ typedef int (*en50221_app_mmi_flush_download_callback)(void *arg, uint8_t slot_i * @param text_size Size of text data. * @return 0 on success, -1 on failure. */ -typedef int (*en50221_app_mmi_enq_callback)(void *arg, uint8_t slot_id, uint16_t session_number, - uint8_t blind_answer, uint8_t expected_answer_length, - uint8_t *text, uint32_t text_size); +typedef int (*en50221_app_mmi_enq_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number, + uint8_t blind_answer, + uint8_t expected_answer_length, + uint8_t * text, + uint32_t text_size); /** * Type definition for menu callback. @@ -270,12 +298,16 @@ typedef int (*en50221_app_mmi_enq_callback)(void *arg, uint8_t slot_id, uint16_t * @param items_raw If nonstandard items were supplied, pointer to their data. * @return 0 on success, -1 on failure. */ -typedef int (*en50221_app_mmi_menu_callback)(void *arg, uint8_t slot_id, uint16_t session_number, - struct en50221_app_mmi_text *title, - struct en50221_app_mmi_text *sub_title, - struct en50221_app_mmi_text *bottom, - uint32_t item_count, struct en50221_app_mmi_text *items, - uint32_t item_raw_length, uint8_t *items_raw); +typedef int (*en50221_app_mmi_menu_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number, + struct en50221_app_mmi_text *title, + struct en50221_app_mmi_text *sub_title, + struct en50221_app_mmi_text *bottom, + uint32_t item_count, + struct en50221_app_mmi_text *items, + uint32_t item_raw_length, + uint8_t *items_raw); /** * Type definition for list callback. @@ -292,17 +324,21 @@ typedef int (*en50221_app_mmi_menu_callback)(void *arg, uint8_t slot_id, uint16_ * @param items_raw If nonstandard items were supplied, pointer to their data. * @return 0 on success, -1 on failure. */ -typedef int (*en50221_app_mmi_list_callback)(void *arg, uint8_t slot_id, uint16_t session_number, - struct en50221_app_mmi_text *title, - struct en50221_app_mmi_text *sub_title, - struct en50221_app_mmi_text *bottom, - uint32_t item_count, struct en50221_app_mmi_text *items, - uint32_t item_raw_length, uint8_t *items_raw); +typedef int (*en50221_app_mmi_list_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number, + struct en50221_app_mmi_text *title, + struct en50221_app_mmi_text *sub_title, + struct en50221_app_mmi_text *bottom, + uint32_t item_count, + struct en50221_app_mmi_text *items, + uint32_t item_raw_length, + uint8_t *items_raw); /** * Opaque type representing a mmi resource. */ -typedef void *en50221_app_mmi; +struct en50221_app_mmi; /** * Create an instance of the mmi resource. @@ -310,14 +346,14 @@ typedef void *en50221_app_mmi; * @param funcs Send functions to use. * @return Instance, or NULL on failure. */ -extern en50221_app_mmi en50221_app_mmi_create(struct en50221_app_send_functions *funcs); +extern struct en50221_app_mmi *en50221_app_mmi_create(struct en50221_app_send_functions *funcs); /** * Destroy an instance of the mmi resource. * * @param mmi Instance to destroy. */ -extern void en50221_app_mmi_destroy(en50221_app_mmi mmi); +extern void en50221_app_mmi_destroy(struct en50221_app_mmi *mmi); /** * Informs the mmi object that a session to it has been closed - cleans up internal state. @@ -325,7 +361,8 @@ extern void en50221_app_mmi_destroy(en50221_app_mmi mmi); * @param mmi mmi resource instance. * @param session_number The session concerned. */ -extern void en50221_app_mmi_clear_session(en50221_app_mmi mmi, uint16_t session_number); +extern void en50221_app_mmi_clear_session(struct en50221_app_mmi *mmi, + uint16_t session_number); /** * Register the callback for when we receive an mmi_close request. @@ -334,8 +371,9 @@ extern void en50221_app_mmi_clear_session(en50221_app_mmi mmi, uint16_t session_ * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_app_mmi_register_close_callback(en50221_app_mmi mmi, - en50221_app_mmi_close_callback callback, void *arg); +extern void en50221_app_mmi_register_close_callback(struct en50221_app_mmi *mmi, + en50221_app_mmi_close_callback callback, + void *arg); /** * Register the callback for when we receive a display control request. @@ -344,8 +382,9 @@ extern void en50221_app_mmi_register_close_callback(en50221_app_mmi mmi, * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_app_mmi_register_display_control_callback(en50221_app_mmi mmi, - en50221_app_mmi_display_control_callback callback, void *arg); +extern void en50221_app_mmi_register_display_control_callback(struct en50221_app_mmi *mmi, + en50221_app_mmi_display_control_callback callback, + void *arg); /** * Register the callback for when we receive a keypad control request. @@ -354,8 +393,9 @@ extern void en50221_app_mmi_register_display_control_callback(en50221_app_mmi mm * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_app_mmi_register_keypad_control_callback(en50221_app_mmi mmi, - en50221_app_mmi_keypad_control_callback callback, void *arg); +extern void en50221_app_mmi_register_keypad_control_callback(struct en50221_app_mmi *mmi, + en50221_app_mmi_keypad_control_callback callback, + void *arg); /** * Register the callback for when we receive a subtitle segment request. @@ -364,8 +404,9 @@ extern void en50221_app_mmi_register_keypad_control_callback(en50221_app_mmi mmi * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_app_mmi_register_subtitle_segment_callback(en50221_app_mmi mmi, - en50221_app_mmi_subtitle_segment_callback callback, void *arg); +extern void en50221_app_mmi_register_subtitle_segment_callback(struct en50221_app_mmi *mmi, + en50221_app_mmi_subtitle_segment_callback callback, + void *arg); /** * Register the callback for when we receive a scene end mark request. @@ -374,8 +415,9 @@ extern void en50221_app_mmi_register_subtitle_segment_callback(en50221_app_mmi m * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_app_mmi_register_scene_end_mark_callback(en50221_app_mmi mmi, - en50221_app_mmi_scene_end_mark_callback callback, void *arg); +extern void en50221_app_mmi_register_scene_end_mark_callback(struct en50221_app_mmi *mmi, + en50221_app_mmi_scene_end_mark_callback callback, + void *arg); /** * Register the callback for when we receive a scene control request. @@ -384,8 +426,9 @@ extern void en50221_app_mmi_register_scene_end_mark_callback(en50221_app_mmi mmi * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_app_mmi_register_scene_control_callback(en50221_app_mmi mmi, - en50221_app_mmi_scene_control_callback callback, void *arg); +extern void en50221_app_mmi_register_scene_control_callback(struct en50221_app_mmi *mmi, + en50221_app_mmi_scene_control_callback callback, + void *arg); /** * Register the callback for when we receive a subtitle download request. @@ -394,8 +437,9 @@ extern void en50221_app_mmi_register_scene_control_callback(en50221_app_mmi mmi, * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_app_mmi_register_subtitle_download_callback(en50221_app_mmi mmi, - en50221_app_mmi_subtitle_download_callback callback, void *arg); +extern void en50221_app_mmi_register_subtitle_download_callback(struct en50221_app_mmi *mmi, + en50221_app_mmi_subtitle_download_callback callback, + void *arg); /** * Register the callback for when we receive a flush download request. @@ -404,8 +448,9 @@ extern void en50221_app_mmi_register_subtitle_download_callback(en50221_app_mmi * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_app_mmi_register_flush_download_callback(en50221_app_mmi mmi, - en50221_app_mmi_flush_download_callback callback, void *arg); +extern void en50221_app_mmi_register_flush_download_callback(struct en50221_app_mmi *mmi, + en50221_app_mmi_flush_download_callback callback, + void *arg); /** * Register the callback for when we receive an enq request. @@ -414,8 +459,9 @@ extern void en50221_app_mmi_register_flush_download_callback(en50221_app_mmi mmi * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_app_mmi_register_enq_callback(en50221_app_mmi mmi, - en50221_app_mmi_enq_callback callback, void *arg); +extern void en50221_app_mmi_register_enq_callback(struct en50221_app_mmi *mmi, + en50221_app_mmi_enq_callback callback, + void *arg); /** * Register the callback for when we receive a menu request. @@ -424,8 +470,9 @@ extern void en50221_app_mmi_register_enq_callback(en50221_app_mmi mmi, * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_app_mmi_register_menu_callback(en50221_app_mmi mmi, - en50221_app_mmi_menu_callback callback, void *arg); +extern void en50221_app_mmi_register_menu_callback(struct en50221_app_mmi *mmi, + en50221_app_mmi_menu_callback callback, + void *arg); /** * Register the callback for when we receive a list request. @@ -434,8 +481,9 @@ extern void en50221_app_mmi_register_menu_callback(en50221_app_mmi mmi, * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_app_mmi_register_list_callback(en50221_app_mmi mmi, - en50221_app_mmi_list_callback callback, void *arg); +extern void en50221_app_mmi_register_list_callback(struct en50221_app_mmi *mmi, + en50221_app_mmi_list_callback callback, + void *arg); /** * Send an mmi_close to the cam. @@ -446,10 +494,9 @@ extern void en50221_app_mmi_register_list_callback(en50221_app_mmi mmi, * @param delay Delay to use if MMI_CLOSE_MMI_CMD_ID_DELAY specified. * @return 0 on success, -1 on failure. */ -extern int en50221_app_mmi_close(en50221_app_mmi mmi, - uint16_t session_number, - uint8_t cmd_id, - uint8_t delay); +extern int en50221_app_mmi_close(struct en50221_app_mmi *mmi, + uint16_t session_number, + uint8_t cmd_id, uint8_t delay); /** * Send a display_reply to the cam. @@ -460,10 +507,10 @@ extern int en50221_app_mmi_close(en50221_app_mmi mmi, * @param details The details of the reply - can be NULL if the chosen reply_id does not need it. * @return 0 on success, -1 on failure. */ -extern int en50221_app_mmi_display_reply(en50221_app_mmi mmi, - uint16_t session_number, - uint8_t reply_id, - struct en502221_app_mmi_display_reply_details *details); +extern int en50221_app_mmi_display_reply(struct en50221_app_mmi *mmi, + uint16_t session_number, + uint8_t reply_id, + struct en50221_app_mmi_display_reply_details *details); /** * Send a keypress to the cam. @@ -473,9 +520,9 @@ extern int en50221_app_mmi_display_reply(en50221_app_mmi mmi, * @param keycode The keycode. * @return 0 on success, -1 on failure. */ -extern int en50221_app_mmi_keypress(en50221_app_mmi mmi, - uint16_t session_number, - uint8_t keycode); +extern int en50221_app_mmi_keypress(struct en50221_app_mmi *mmi, + uint16_t session_number, + uint8_t keycode); /** * Send a display message to the cam. @@ -485,9 +532,9 @@ extern int en50221_app_mmi_keypress(en50221_app_mmi mmi, * @param display_message_id One of the MMI_DISPLAY_MESSAGE_ID_* values. * @return 0 on success, -1 on failure. */ -extern int en50221_app_mmi_display_message(en50221_app_mmi mmi, - uint16_t session_number, - uint8_t display_message_id); +extern int en50221_app_mmi_display_message(struct en50221_app_mmi *mmi, + uint16_t session_number, + uint8_t display_message_id); /** * Send a scene done message to the cam. @@ -499,11 +546,11 @@ extern int en50221_app_mmi_display_message(en50221_app_mmi mmi, * @param scene_tag Scene tag this responds to. * @return 0 on success, -1 on failure. */ -extern int en50221_app_mmi_scene_done(en50221_app_mmi mmi, - uint16_t session_number, - uint8_t decoder_continue, - uint8_t scene_reveal, - uint8_t scene_tag); +extern int en50221_app_mmi_scene_done(struct en50221_app_mmi *mmi, + uint16_t session_number, + uint8_t decoder_continue, + uint8_t scene_reveal, + uint8_t scene_tag); /** * Send a download reply to the cam. @@ -514,10 +561,10 @@ extern int en50221_app_mmi_scene_done(en50221_app_mmi mmi, * @param download_reply_id One of the MMI_DOWNLOAD_REPLY_ID_* values. * @return 0 on success, -1 on failure. */ -extern int en50221_app_mmi_download_reply(en50221_app_mmi mmi, - uint16_t session_number, - uint16_t object_id, - uint8_t download_reply_id); +extern int en50221_app_mmi_download_reply(struct en50221_app_mmi *mmi, + uint16_t session_number, + uint16_t object_id, + uint8_t download_reply_id); /** * Send an answ to the cam. @@ -529,11 +576,11 @@ extern int en50221_app_mmi_download_reply(en50221_app_mmi mmi, * @param text_count Length of text. * @return 0 on success, -1 on failure. */ -extern int en50221_app_mmi_answ(en50221_app_mmi mmi, - uint16_t session_number, - uint8_t answ_id, - uint8_t *text, - uint32_t text_count); +extern int en50221_app_mmi_answ(struct en50221_app_mmi *mmi, + uint16_t session_number, + uint8_t answ_id, + uint8_t * text, + uint32_t text_count); /** * Send a menu answ to the cam. @@ -543,9 +590,9 @@ extern int en50221_app_mmi_answ(en50221_app_mmi mmi, * @param choice_ref Option chosen by user (0=>canceled). * @return 0 on success, -1 on failure. */ -extern int en50221_app_mmi_menu_answ(en50221_app_mmi mmi, - uint16_t session_number, - uint8_t choice_ref); +extern int en50221_app_mmi_menu_answ(struct en50221_app_mmi *mmi, + uint16_t session_number, + uint8_t choice_ref); /** * Pass data received for this resource into it for parsing. @@ -558,14 +605,14 @@ extern int en50221_app_mmi_menu_answ(en50221_app_mmi mmi, * @param data_length Length of data in bytes. * @return 0 on success, -1 on failure. */ -extern int en50221_app_mmi_message(en50221_app_mmi mmi, - uint8_t slot_id, - uint16_t session_number, - uint32_t resource_id, - uint8_t *data, uint32_t data_length); +extern int en50221_app_mmi_message(struct en50221_app_mmi *mmi, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, + uint32_t data_length); #ifdef __cplusplus } #endif - #endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_rm.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_rm.c index 71f2b19..7a5bc2f 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_rm.c +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_rm.c @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,7 +18,7 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <string.h> @@ -29,266 +29,279 @@ #include "en50221_app_tags.h" #include "asn_1.h" -struct en50221_app_rm_private { - struct en50221_app_send_functions *funcs; +struct en50221_app_rm { + struct en50221_app_send_functions *funcs; - en50221_app_rm_enq_callback enqcallback; - void *enqcallback_arg; + en50221_app_rm_enq_callback enqcallback; + void *enqcallback_arg; - en50221_app_rm_reply_callback replycallback; - void *replycallback_arg; + en50221_app_rm_reply_callback replycallback; + void *replycallback_arg; - en50221_app_rm_changed_callback changedcallback; - void *changedcallback_arg; + en50221_app_rm_changed_callback changedcallback; + void *changedcallback_arg; - pthread_mutex_t lock; + pthread_mutex_t lock; }; -static int en50221_app_rm_parse_profile_enq(struct en50221_app_rm_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length); -static int en50221_app_rm_parse_profile_reply(struct en50221_app_rm_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length); -static int en50221_app_rm_parse_profile_change(struct en50221_app_rm_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length); - - -en50221_app_rm en50221_app_rm_create(struct en50221_app_send_functions *funcs) +static int en50221_app_rm_parse_profile_enq(struct en50221_app_rm *rm, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length); +static int en50221_app_rm_parse_profile_reply(struct en50221_app_rm *rm, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length); +static int en50221_app_rm_parse_profile_change(struct en50221_app_rm *rm, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length); + + +struct en50221_app_rm *en50221_app_rm_create(struct + en50221_app_send_functions + *funcs) { - struct en50221_app_rm_private *private = NULL; - - // create structure and set it up - private = malloc(sizeof(struct en50221_app_rm_private)); - if (private == NULL) { - return NULL; - } - private->funcs = funcs; - private->enqcallback = NULL; - private->replycallback = NULL; - private->changedcallback = NULL; - - pthread_mutex_init(&private->lock, NULL); - - // done - return private; + struct en50221_app_rm *rm = NULL; + + // create structure and set it up + rm = malloc(sizeof(struct en50221_app_rm)); + if (rm == NULL) { + return NULL; + } + rm->funcs = funcs; + rm->enqcallback = NULL; + rm->replycallback = NULL; + rm->changedcallback = NULL; + + pthread_mutex_init(&rm->lock, NULL); + + // done + return rm; } -void en50221_app_rm_destroy(en50221_app_rm rm) +void en50221_app_rm_destroy(struct en50221_app_rm *rm) { - struct en50221_app_rm_private *private = (struct en50221_app_rm_private *) rm; - - pthread_mutex_destroy(&private->lock); - free(private); + pthread_mutex_destroy(&rm->lock); + free(rm); } -void en50221_app_rm_register_enq_callback(en50221_app_rm rm, - en50221_app_rm_enq_callback callback, void *arg) +void en50221_app_rm_register_enq_callback(struct en50221_app_rm *rm, + en50221_app_rm_enq_callback + callback, void *arg) { - struct en50221_app_rm_private *private = (struct en50221_app_rm_private *) rm; - - pthread_mutex_lock(&private->lock); - private->enqcallback = callback; - private->enqcallback_arg = arg; - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&rm->lock); + rm->enqcallback = callback; + rm->enqcallback_arg = arg; + pthread_mutex_unlock(&rm->lock); } -void en50221_app_rm_register_reply_callback(en50221_app_rm rm, - en50221_app_rm_reply_callback callback, void *arg) +void en50221_app_rm_register_reply_callback(struct en50221_app_rm *rm, + en50221_app_rm_reply_callback + callback, void *arg) { - struct en50221_app_rm_private *private = (struct en50221_app_rm_private *) rm; - - pthread_mutex_lock(&private->lock); - private->replycallback = callback; - private->replycallback_arg = arg; - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&rm->lock); + rm->replycallback = callback; + rm->replycallback_arg = arg; + pthread_mutex_unlock(&rm->lock); } -void en50221_app_rm_register_changed_callback(en50221_app_rm rm, - en50221_app_rm_changed_callback callback, void *arg) +void en50221_app_rm_register_changed_callback(struct en50221_app_rm *rm, + en50221_app_rm_changed_callback + callback, void *arg) { - struct en50221_app_rm_private *private = (struct en50221_app_rm_private *) rm; - - pthread_mutex_lock(&private->lock); - private->changedcallback = callback; - private->changedcallback_arg = arg; - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&rm->lock); + rm->changedcallback = callback; + rm->changedcallback_arg = arg; + pthread_mutex_unlock(&rm->lock); } -int en50221_app_rm_enq(en50221_app_rm rm, uint16_t session_number) +int en50221_app_rm_enq(struct en50221_app_rm *rm, uint16_t session_number) { - struct en50221_app_rm_private *private = (struct en50221_app_rm_private *) rm; - uint8_t buf[4]; + uint8_t buf[4]; - // set up the tag - buf[0] = (TAG_PROFILE_ENQUIRY >> 16) & 0xFF; - buf[1] = (TAG_PROFILE_ENQUIRY >> 8) & 0xFF; - buf[2] = TAG_PROFILE_ENQUIRY & 0xFF; - buf[3] = 0; + // set up the tag + buf[0] = (TAG_PROFILE_ENQUIRY >> 16) & 0xFF; + buf[1] = (TAG_PROFILE_ENQUIRY >> 8) & 0xFF; + buf[2] = TAG_PROFILE_ENQUIRY & 0xFF; + buf[3] = 0; - // create the data and send it - return private->funcs->send_data(private->funcs->arg, session_number, buf, 4); + // create the data and send it + return rm->funcs->send_data(rm->funcs->arg, session_number, buf, 4); } -int en50221_app_rm_reply(en50221_app_rm rm, uint16_t session_number, - uint32_t resource_id_count, - uint32_t *resource_ids) +int en50221_app_rm_reply(struct en50221_app_rm *rm, + uint16_t session_number, + uint32_t resource_id_count, + uint32_t * resource_ids) { - struct en50221_app_rm_private *private = (struct en50221_app_rm_private *) rm; - uint8_t buf[10]; - - // set up the tag - buf[0] = (TAG_PROFILE >> 16) & 0xFF; - buf[1] = (TAG_PROFILE >> 8) & 0xFF; - buf[2] = TAG_PROFILE & 0xFF; - - // encode the length field - int length_field_len; - if ((length_field_len = asn_1_encode(resource_id_count*4, buf+3, 3)) < 0) { - return -1; - } - - // copy the data and byteswap it - uint32_t *copy_resource_ids = alloca(4*resource_id_count); - if (copy_resource_ids == NULL) { - return -1; - } - uint8_t *data = (uint8_t*) copy_resource_ids; - memcpy(data, resource_ids, resource_id_count*4); - uint32_t i; - for(i=0; i<resource_id_count; i++) { - bswap32(data); - data+=4; - } - - // build the iovecs - struct iovec iov[2]; - iov[0].iov_base = buf; - iov[0].iov_len = 3+length_field_len; - iov[1].iov_base = (uint8_t*) copy_resource_ids; - iov[1].iov_len = resource_id_count * 4; - - // create the data and send it - return private->funcs->send_datav(private->funcs->arg, session_number, iov, 2); + uint8_t buf[10]; + + // set up the tag + buf[0] = (TAG_PROFILE >> 16) & 0xFF; + buf[1] = (TAG_PROFILE >> 8) & 0xFF; + buf[2] = TAG_PROFILE & 0xFF; + + // encode the length field + int length_field_len; + if ((length_field_len = asn_1_encode(resource_id_count * 4, buf + 3, 3)) < 0) { + return -1; + } + // copy the data and byteswap it + uint32_t *copy_resource_ids = alloca(4 * resource_id_count); + if (copy_resource_ids == NULL) { + return -1; + } + uint8_t *data = (uint8_t *) copy_resource_ids; + memcpy(data, resource_ids, resource_id_count * 4); + uint32_t i; + for (i = 0; i < resource_id_count; i++) { + bswap32(data); + data += 4; + } + + // build the iovecs + struct iovec iov[2]; + iov[0].iov_base = buf; + iov[0].iov_len = 3 + length_field_len; + iov[1].iov_base = (uint8_t *) copy_resource_ids; + iov[1].iov_len = resource_id_count * 4; + + // create the data and send it + return rm->funcs->send_datav(rm->funcs->arg, session_number, iov, 2); } -int en50221_app_rm_changed(en50221_app_rm rm, uint16_t session_number) +int en50221_app_rm_changed(struct en50221_app_rm *rm, + uint16_t session_number) { - struct en50221_app_rm_private *private = (struct en50221_app_rm_private *) rm; - uint8_t buf[4]; + uint8_t buf[4]; - // set up the tag - buf[0] = (TAG_PROFILE_CHANGE >> 16) & 0xFF; - buf[1] = (TAG_PROFILE_CHANGE >> 8) & 0xFF; - buf[2] = TAG_PROFILE_CHANGE & 0xFF; - buf[3] = 0; + // set up the tag + buf[0] = (TAG_PROFILE_CHANGE >> 16) & 0xFF; + buf[1] = (TAG_PROFILE_CHANGE >> 8) & 0xFF; + buf[2] = TAG_PROFILE_CHANGE & 0xFF; + buf[3] = 0; - // create the data and send it - return private->funcs->send_data(private->funcs->arg, session_number, buf, 4); + // create the data and send it + return rm->funcs->send_data(rm->funcs->arg, session_number, buf, 4); } -int en50221_app_rm_message(en50221_app_rm rm, - uint8_t slot_id, - uint16_t session_number, - uint32_t resource_id, - uint8_t *data, uint32_t data_length) +int en50221_app_rm_message(struct en50221_app_rm *rm, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t * data, uint32_t data_length) { - struct en50221_app_rm_private *private = (struct en50221_app_rm_private *) rm; - (void) resource_id; - - // get the tag - if (data_length < 3) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; - - // dispatch it - switch(tag) - { - case TAG_PROFILE_ENQUIRY: - return en50221_app_rm_parse_profile_enq(private, slot_id, session_number, data+3, data_length-3); - case TAG_PROFILE: - return en50221_app_rm_parse_profile_reply(private, slot_id, session_number, data+3, data_length-3); - case TAG_PROFILE_CHANGE: - return en50221_app_rm_parse_profile_change(private, slot_id, session_number, data+3, data_length-3); - } - - print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); - return -1; + (void) resource_id; + + // get the tag + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; + + // dispatch it + switch (tag) { + case TAG_PROFILE_ENQUIRY: + return en50221_app_rm_parse_profile_enq(rm, slot_id, + session_number, + data + 3, + data_length - 3); + case TAG_PROFILE: + return en50221_app_rm_parse_profile_reply(rm, slot_id, + session_number, + data + 3, + data_length - 3); + case TAG_PROFILE_CHANGE: + return en50221_app_rm_parse_profile_change(rm, slot_id, + session_number, + data + 3, + data_length - 3); + } + + print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); + return -1; } -static int en50221_app_rm_parse_profile_enq(struct en50221_app_rm_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length) +static int en50221_app_rm_parse_profile_enq(struct en50221_app_rm *rm, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length) { - (void)data; - (void)data_length; - - pthread_mutex_lock(&private->lock); - en50221_app_rm_enq_callback cb = private->enqcallback; - void *cb_arg = private->enqcallback_arg; - pthread_mutex_unlock(&private->lock); - if (cb) { - return cb(cb_arg, slot_id, session_number); - } - return 0; + (void) data; + (void) data_length; + + pthread_mutex_lock(&rm->lock); + en50221_app_rm_enq_callback cb = rm->enqcallback; + void *cb_arg = rm->enqcallback_arg; + pthread_mutex_unlock(&rm->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number); + } + return 0; } -static int en50221_app_rm_parse_profile_reply(struct en50221_app_rm_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length) +static int en50221_app_rm_parse_profile_reply(struct en50221_app_rm *rm, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length) { - // first of all, decode the length field - uint16_t asn_data_length; - int length_field_len; - if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { - print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); - return -1; - } - - // check it - if (asn_data_length > (data_length-length_field_len)) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - uint32_t resources_count = asn_data_length / 4; - uint32_t *resource_ids = (uint32_t*) (data+length_field_len); - data += length_field_len; - - // byteswap it - uint32_t i; - for(i=0; i< resources_count; i++) { - bswap32(data); - data+=4; - } - - // inform observer - pthread_mutex_lock(&private->lock); - en50221_app_rm_reply_callback cb = private->replycallback; - void *cb_arg = private->replycallback_arg; - pthread_mutex_unlock(&private->lock); - if (cb) { - return cb(cb_arg, slot_id, session_number, resources_count, resource_ids); - } - return 0; + // first of all, decode the length field + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); + return -1; + } + // check it + if (asn_data_length > (data_length - length_field_len)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint32_t resources_count = asn_data_length / 4; + uint32_t *resource_ids = (uint32_t *) (data + length_field_len); + data += length_field_len; + + // byteswap it + uint32_t i; + for (i = 0; i < resources_count; i++) { + bswap32(data); + data += 4; + } + + // inform observer + pthread_mutex_lock(&rm->lock); + en50221_app_rm_reply_callback cb = rm->replycallback; + void *cb_arg = rm->replycallback_arg; + pthread_mutex_unlock(&rm->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, resources_count, resource_ids); + } + return 0; } -static int en50221_app_rm_parse_profile_change(struct en50221_app_rm_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length) +static int en50221_app_rm_parse_profile_change(struct en50221_app_rm *rm, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length) { - (void)data; - (void)data_length; - - pthread_mutex_lock(&private->lock); - en50221_app_rm_changed_callback cb = private->changedcallback; - void *cb_arg = private->changedcallback_arg; - pthread_mutex_unlock(&private->lock); - if (cb) { - return cb(cb_arg, slot_id, session_number); - } - return 0; + (void) data; + (void) data_length; + + pthread_mutex_lock(&rm->lock); + en50221_app_rm_changed_callback cb = rm->changedcallback; + void *cb_arg = rm->changedcallback_arg; + pthread_mutex_unlock(&rm->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number); + } + return 0; } diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_rm.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_rm.h index aa91ff5..ec97372 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_rm.h +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_rm.h @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,15 +18,14 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __EN50221_APPLICATION_RM_H__ #define __EN50221_APPLICATION_RM_H__ #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif #include <stdlib.h> @@ -44,7 +43,9 @@ extern "C" * @param session_number Session number concerned. * @return 0 on success, -1 on failure. */ -typedef int (*en50221_app_rm_enq_callback)(void *arg, uint8_t slot_id, uint16_t session_number); +typedef int (*en50221_app_rm_enq_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number); /** * Type definition for profile_reply callback function - called when we receive @@ -57,9 +58,11 @@ typedef int (*en50221_app_rm_enq_callback)(void *arg, uint8_t slot_id, uint16_t * @param resource_ids The resource ids themselves. * @return 0 on success, -1 on failure. */ -typedef int (*en50221_app_rm_reply_callback)(void *arg, uint8_t slot_id, uint16_t session_number, - uint32_t resource_id_count, - uint32_t *resource_ids); +typedef int (*en50221_app_rm_reply_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id_count, + uint32_t *resource_ids); /** * Type definition for profile_changed callback function - called when we receive * a profile_changed from a CAM. @@ -69,14 +72,16 @@ typedef int (*en50221_app_rm_reply_callback)(void *arg, uint8_t slot_id, uint16_ * @param session_number Session number concerned. * @return 0 on success, -1 on failure. */ -typedef int (*en50221_app_rm_changed_callback)(void *arg, uint8_t slot_id, uint16_t session_number); +typedef int (*en50221_app_rm_changed_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number); /** * Opaque type representing a resource manager. */ -typedef void *en50221_app_rm; +struct en50221_app_rm; /** * Create an instance of the resource manager. @@ -84,14 +89,14 @@ typedef void *en50221_app_rm; * @param funcs Send functions to use. * @return Instance, or NULL on failure. */ -extern en50221_app_rm en50221_app_rm_create(struct en50221_app_send_functions *funcs); +extern struct en50221_app_rm *en50221_app_rm_create(struct en50221_app_send_functions *funcs); /** * Destroy an instance of the resource manager. * * @param rm Instance to destroy. */ -extern void en50221_app_rm_destroy(en50221_app_rm rm); +extern void en50221_app_rm_destroy(struct en50221_app_rm *rm); /** * Register the callback for when we receive a profile_enq from a CAM. @@ -100,8 +105,9 @@ extern void en50221_app_rm_destroy(en50221_app_rm rm); * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_app_rm_register_enq_callback(en50221_app_rm rm, - en50221_app_rm_enq_callback callback, void *arg); +extern void en50221_app_rm_register_enq_callback(struct en50221_app_rm *rm, + en50221_app_rm_enq_callback callback, + void *arg); /** * Register the callback for when we receive a profile_reply from a CAM. @@ -110,8 +116,9 @@ extern void en50221_app_rm_register_enq_callback(en50221_app_rm rm, * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_app_rm_register_reply_callback(en50221_app_rm rm, - en50221_app_rm_reply_callback callback, void *arg); +extern void en50221_app_rm_register_reply_callback(struct en50221_app_rm *rm, + en50221_app_rm_reply_callback callback, + void *arg); /** * Register the callback for when we receive a profile_changed from a CAM. @@ -120,8 +127,9 @@ extern void en50221_app_rm_register_reply_callback(en50221_app_rm rm, * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_app_rm_register_changed_callback(en50221_app_rm rm, - en50221_app_rm_changed_callback callback, void *arg); +extern void en50221_app_rm_register_changed_callback(struct en50221_app_rm *rm, + en50221_app_rm_changed_callback callback, + void *arg); /** * Send a profile_enq to a CAM. @@ -130,7 +138,7 @@ extern void en50221_app_rm_register_changed_callback(en50221_app_rm rm, * @param session_number Session number to send it on. * @return 0 on success, -1 on failure. */ -extern int en50221_app_rm_enq(en50221_app_rm rm, uint16_t session_number); +extern int en50221_app_rm_enq(struct en50221_app_rm *rm, uint16_t session_number); /** * Send a profile_reply to a CAM. @@ -141,9 +149,10 @@ extern int en50221_app_rm_enq(en50221_app_rm rm, uint16_t session_number); * @param resource_ids The resource IDs themselves * @return 0 on success, -1 on failure. */ -extern int en50221_app_rm_reply(en50221_app_rm rm, uint16_t session_number, - uint32_t resource_id_count, - uint32_t *resource_ids); +extern int en50221_app_rm_reply(struct en50221_app_rm *rm, + uint16_t session_number, + uint32_t resource_id_count, + uint32_t * resource_ids); /** * Send a profile_changed to a CAM. @@ -152,7 +161,7 @@ extern int en50221_app_rm_reply(en50221_app_rm rm, uint16_t session_number, * @param session_number Session number to send it on. * @return 0 on success, -1 on failure. */ -extern int en50221_app_rm_changed(en50221_app_rm rm, uint16_t session_number); +extern int en50221_app_rm_changed(struct en50221_app_rm *rm, uint16_t session_number); /** * Pass data received for this resource into it for parsing. @@ -165,14 +174,14 @@ extern int en50221_app_rm_changed(en50221_app_rm rm, uint16_t session_number); * @param data_length Length of data in bytes. * @return 0 on success, -1 on failure. */ -extern int en50221_app_rm_message(en50221_app_rm rm, - uint8_t slot_id, - uint16_t session_number, - uint32_t resource_id, - uint8_t *data, uint32_t data_length); +extern int en50221_app_rm_message(struct en50221_app_rm *rm, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, + uint32_t data_length); #ifdef __cplusplus } #endif - #endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_smartcard.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_smartcard.c index c0f6961..763c6c4 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_smartcard.c +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_smartcard.c @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,7 +18,7 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <string.h> @@ -28,188 +28,186 @@ #include "en50221_app_tags.h" #include "asn_1.h" -struct en50221_app_smartcard_private { - struct en50221_app_send_functions *funcs; +struct en50221_app_smartcard { + struct en50221_app_send_functions *funcs; - en50221_app_smartcard_command_callback command_callback; - void *command_callback_arg; + en50221_app_smartcard_command_callback command_callback; + void *command_callback_arg; - en50221_app_smartcard_send_callback send_callback; - void *send_callback_arg; + en50221_app_smartcard_send_callback send_callback; + void *send_callback_arg; - pthread_mutex_t lock; + pthread_mutex_t lock; }; -static int en50221_app_smartcard_parse_command(struct en50221_app_smartcard_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length); +static int en50221_app_smartcard_parse_command(struct en50221_app_smartcard *smartcard, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length); -static int en50221_app_smartcard_parse_send(struct en50221_app_smartcard_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length); +static int en50221_app_smartcard_parse_send(struct en50221_app_smartcard *smartcard, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length); -en50221_app_smartcard en50221_app_smartcard_create(struct en50221_app_send_functions *funcs) +struct en50221_app_smartcard *en50221_app_smartcard_create(struct en50221_app_send_functions *funcs) { - struct en50221_app_smartcard_private *private = NULL; + struct en50221_app_smartcard *smartcard = NULL; - // create structure and set it up - private = malloc(sizeof(struct en50221_app_smartcard_private)); - if (private == NULL) { - return NULL; - } - private->funcs = funcs; - private->command_callback = NULL; - private->send_callback = NULL; + // create structure and set it up + smartcard = malloc(sizeof(struct en50221_app_smartcard)); + if (smartcard == NULL) { + return NULL; + } + smartcard->funcs = funcs; + smartcard->command_callback = NULL; + smartcard->send_callback = NULL; - pthread_mutex_init(&private->lock, NULL); + pthread_mutex_init(&smartcard->lock, NULL); - // done - return private; + // done + return smartcard; } -void en50221_app_smartcard_destroy(en50221_app_smartcard smartcard) +void en50221_app_smartcard_destroy(struct en50221_app_smartcard *smartcard) { - struct en50221_app_smartcard_private *private = (struct en50221_app_smartcard_private *) smartcard; - - pthread_mutex_destroy(&private->lock); - free(private); + pthread_mutex_destroy(&smartcard->lock); + free(smartcard); } -void en50221_app_smartcard_register_command_callback(en50221_app_smartcard smartcard, - en50221_app_smartcard_command_callback callback, void *arg) +void en50221_app_smartcard_register_command_callback(struct en50221_app_smartcard *smartcard, + en50221_app_smartcard_command_callback callback, void *arg) { - struct en50221_app_smartcard_private *private = (struct en50221_app_smartcard_private *) smartcard; - - pthread_mutex_lock(&private->lock); - private->command_callback = callback; - private->command_callback_arg = arg; - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&smartcard->lock); + smartcard->command_callback = callback; + smartcard->command_callback_arg = arg; + pthread_mutex_unlock(&smartcard->lock); } -void en50221_app_smartcard_register_send_callback(en50221_app_smartcard smartcard, - en50221_app_smartcard_send_callback callback, void *arg) +void en50221_app_smartcard_register_send_callback(struct en50221_app_smartcard *smartcard, + en50221_app_smartcard_send_callback callback, void *arg) { - struct en50221_app_smartcard_private *private = (struct en50221_app_smartcard_private *) smartcard; - - pthread_mutex_lock(&private->lock); - private->send_callback = callback; - private->send_callback_arg = arg; - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&smartcard->lock); + smartcard->send_callback = callback; + smartcard->send_callback_arg = arg; + pthread_mutex_unlock(&smartcard->lock); } -int en50221_app_smartcard_command_reply(en50221_app_smartcard smartcard, - uint16_t session_number, - uint8_t reply_id, - uint8_t status, - uint8_t *data, - uint32_t data_length) +int en50221_app_smartcard_command_reply(struct en50221_app_smartcard *smartcard, + uint16_t session_number, + uint8_t reply_id, uint8_t status, + uint8_t *data, + uint32_t data_length) { - struct en50221_app_smartcard_private *private = (struct en50221_app_smartcard_private *) smartcard; - uint8_t hdr[10]; - struct iovec iovec[2]; - int iov_count = 0; - - // the tag - hdr[0] = (TAG_SMARTCARD_REPLY >> 16) & 0xFF; - hdr[1] = (TAG_SMARTCARD_REPLY >> 8) & 0xFF; - hdr[2] = TAG_SMARTCARD_REPLY & 0xFF; - - // the rest of the data - if (reply_id == SMARTCARD_REPLY_ID_ANSW_TO_RESET) { - // encode the length field - int length_field_len; - if ((length_field_len = asn_1_encode(data_length+2, data+3, 3)) < 0) { - return -1; - } - - // the rest of the header - hdr[3+length_field_len] = reply_id; - hdr[3+length_field_len+1] = status; - iovec[0].iov_base = hdr; - iovec[0].iov_len = 3+length_field_len+2; - - // the data - iovec[1].iov_base = data; - iovec[1].iov_len = data_length; - iov_count = 2; - } else { - hdr[3] = 2; - hdr[4] = reply_id; - hdr[5] = status; - iovec[0].iov_base = data; - iovec[0].iov_len = 6; - iov_count = 1; - } - - return private->funcs->send_datav(private->funcs->arg, session_number, iovec, iov_count); + uint8_t hdr[10]; + struct iovec iovec[2]; + int iov_count = 0; + + // the tag + hdr[0] = (TAG_SMARTCARD_REPLY >> 16) & 0xFF; + hdr[1] = (TAG_SMARTCARD_REPLY >> 8) & 0xFF; + hdr[2] = TAG_SMARTCARD_REPLY & 0xFF; + + // the rest of the data + if (reply_id == SMARTCARD_REPLY_ID_ANSW_TO_RESET) { + // encode the length field + int length_field_len; + if ((length_field_len = asn_1_encode(data_length + 2, data + 3, 3)) < 0) { + return -1; + } + // the rest of the header + hdr[3 + length_field_len] = reply_id; + hdr[3 + length_field_len + 1] = status; + iovec[0].iov_base = hdr; + iovec[0].iov_len = 3 + length_field_len + 2; + + // the data + iovec[1].iov_base = data; + iovec[1].iov_len = data_length; + iov_count = 2; + } else { + hdr[3] = 2; + hdr[4] = reply_id; + hdr[5] = status; + iovec[0].iov_base = data; + iovec[0].iov_len = 6; + iov_count = 1; + } + + return smartcard->funcs->send_datav(smartcard->funcs->arg, session_number, iovec, iov_count); } -int en50221_app_smartcard_receive(en50221_app_smartcard smartcard, - uint16_t session_number, - uint8_t *data, - uint32_t data_length, - uint8_t SW1, - uint8_t SW2) +int en50221_app_smartcard_receive(struct en50221_app_smartcard *smartcard, + uint16_t session_number, + uint8_t *data, + uint32_t data_length, + uint8_t SW1, uint8_t SW2) { - struct en50221_app_smartcard_private *private = (struct en50221_app_smartcard_private *) smartcard; - uint8_t buf[10]; - uint8_t trailer[10]; - - // set up the tag - buf[0] = (TAG_SMARTCARD_RCV >> 16) & 0xFF; - buf[1] = (TAG_SMARTCARD_RCV >> 8) & 0xFF; - buf[2] = TAG_SMARTCARD_RCV & 0xFF; - - // encode the length field - int length_field_len; - if ((length_field_len = asn_1_encode(data_length+2, buf+3, 3)) < 0) { - return -1; - } - - // set up the trailer - trailer[0] = SW1; - trailer[1] = SW2; - - // build the iovecs - struct iovec iov[3]; - iov[0].iov_base = buf; - iov[0].iov_len = 3+length_field_len; - iov[1].iov_base = data; - iov[1].iov_len = data_length; - iov[2].iov_base = trailer; - iov[2].iov_len = 2; - - // create the data and send it - return private->funcs->send_datav(private->funcs->arg, session_number, iov, 3); + uint8_t buf[10]; + uint8_t trailer[10]; + + // set up the tag + buf[0] = (TAG_SMARTCARD_RCV >> 16) & 0xFF; + buf[1] = (TAG_SMARTCARD_RCV >> 8) & 0xFF; + buf[2] = TAG_SMARTCARD_RCV & 0xFF; + + // encode the length field + int length_field_len; + if ((length_field_len = asn_1_encode(data_length + 2, buf + 3, 3)) < 0) { + return -1; + } + // set up the trailer + trailer[0] = SW1; + trailer[1] = SW2; + + // build the iovecs + struct iovec iov[3]; + iov[0].iov_base = buf; + iov[0].iov_len = 3 + length_field_len; + iov[1].iov_base = data; + iov[1].iov_len = data_length; + iov[2].iov_base = trailer; + iov[2].iov_len = 2; + + // create the data and send it + return smartcard->funcs->send_datav(smartcard->funcs->arg, + session_number, iov, 3); } -int en50221_app_smartcard_message(en50221_app_smartcard smartcard, - uint8_t slot_id, - uint16_t session_number, - uint32_t resource_id, - uint8_t *data, uint32_t data_length) +int en50221_app_smartcard_message(struct en50221_app_smartcard *smartcard, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t *data, uint32_t data_length) { - struct en50221_app_smartcard_private *private = (struct en50221_app_smartcard_private *) smartcard; - (void)resource_id; - - // get the tag - if (data_length < 3) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; - - switch(tag) - { - case TAG_SMARTCARD_COMMAND: - return en50221_app_smartcard_parse_command(private, slot_id, session_number, data+3, data_length-3); - case TAG_SMARTCARD_SEND: - return en50221_app_smartcard_parse_send(private, slot_id, session_number, data+3, data_length-3); - } - - print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); - return -1; + (void) resource_id; + + // get the tag + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; + + switch (tag) { + case TAG_SMARTCARD_COMMAND: + return en50221_app_smartcard_parse_command(smartcard, + slot_id, + session_number, + data + 3, + data_length - 3); + case TAG_SMARTCARD_SEND: + return en50221_app_smartcard_parse_send(smartcard, slot_id, + session_number, + data + 3, + data_length - 3); + } + + print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); + return -1; } @@ -218,76 +216,81 @@ int en50221_app_smartcard_message(en50221_app_smartcard smartcard, -static int en50221_app_smartcard_parse_command(struct en50221_app_smartcard_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length) +static int en50221_app_smartcard_parse_command(struct en50221_app_smartcard *smartcard, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length) { - if (data_length != 2) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - if (data[0] != 1) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - uint8_t command_id = data[1]; - - // tell the app - pthread_mutex_lock(&private->lock); - en50221_app_smartcard_command_callback cb = private->command_callback; - void *cb_arg = private->command_callback_arg; - pthread_mutex_unlock(&private->lock); - if (cb) { - return cb(cb_arg, slot_id, session_number, command_id); - } - return 0; + if (data_length != 2) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (data[0] != 1) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint8_t command_id = data[1]; + + // tell the app + pthread_mutex_lock(&smartcard->lock); + en50221_app_smartcard_command_callback cb = smartcard->command_callback; + void *cb_arg = smartcard->command_callback_arg; + pthread_mutex_unlock(&smartcard->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, command_id); + } + return 0; } -static int en50221_app_smartcard_parse_send(struct en50221_app_smartcard_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length) +static int en50221_app_smartcard_parse_send(struct en50221_app_smartcard *smartcard, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length) { - // first of all, decode the length field - uint16_t asn_data_length; - int length_field_len; - if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { - print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); - return -1; - } - - // check it - if (asn_data_length < 8) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - if (asn_data_length > (data_length-length_field_len)) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - data += length_field_len; - - // parse - uint8_t CLA = data[0]; - uint8_t INS = data[1]; - uint8_t P1 = data[2]; - uint8_t P2 = data[3]; - uint16_t length_in = (data[4]<<8)|data[5]; - uint8_t *data_in = data + 6; - - // validate the length - if ((length_in + 8) != asn_data_length) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - uint16_t length_out = (data[6+length_in]<<8)|data[6+length_in+1]; - - // tell the app - pthread_mutex_lock(&private->lock); - en50221_app_smartcard_send_callback cb = private->send_callback; - void *cb_arg = private->send_callback_arg; - pthread_mutex_unlock(&private->lock); - if (cb) { - return cb(cb_arg, slot_id, session_number, CLA, INS, P1, P2, data_in, length_in, length_out); - } - return 0; + // first of all, decode the length field + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); + return -1; + } + // check it + if (asn_data_length < 8) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + if (asn_data_length > (data_length - length_field_len)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + data += length_field_len; + + // parse + uint8_t CLA = data[0]; + uint8_t INS = data[1]; + uint8_t P1 = data[2]; + uint8_t P2 = data[3]; + uint16_t length_in = (data[4] << 8) | data[5]; + uint8_t *data_in = data + 6; + + // validate the length + if ((length_in + 8) != asn_data_length) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint16_t length_out = + (data[6 + length_in] << 8) | data[6 + length_in + 1]; + + // tell the app + pthread_mutex_lock(&smartcard->lock); + en50221_app_smartcard_send_callback cb = smartcard->send_callback; + void *cb_arg = smartcard->send_callback_arg; + pthread_mutex_unlock(&smartcard->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, CLA, INS, P1, + P2, data_in, length_in, length_out); + } + return 0; } diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_smartcard.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_smartcard.h index 546e8be..bbad4a9 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_smartcard.h +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_smartcard.h @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,15 +18,14 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __EN50221_APPLICATION_smartcard_H__ #define __EN50221_APPLICATION_smartcard_H__ #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif #include <stdlib.h> @@ -68,8 +67,10 @@ extern "C" * @param command_id One of the SMARTCARD_COMMAND_ID_* values * @return 0 on success, -1 on failure. */ -typedef int (*en50221_app_smartcard_command_callback)(void *arg, uint8_t slot_id, uint16_t session_number, - uint8_t command_id); +typedef int (*en50221_app_smartcard_command_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number, + uint8_t command_id); /** * Type definition for command - called when we receive a send command. @@ -86,15 +87,21 @@ typedef int (*en50221_app_smartcard_command_callback)(void *arg, uint8_t slot_id * @param out_length Number of bytes expected. * @return 0 on success, -1 on failure. */ -typedef int (*en50221_app_smartcard_send_callback)(void *arg, uint8_t slot_id, uint16_t session_number, - uint8_t CLA, uint8_t INS, uint8_t P1, uint8_t P2, - uint8_t *in, uint32_t in_length, - uint32_t out_length); +typedef int (*en50221_app_smartcard_send_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number, + uint8_t CLA, + uint8_t INS, + uint8_t P1, + uint8_t P2, + uint8_t *in, + uint32_t in_length, + uint32_t out_length); /** * Opaque type representing a smartcard resource. */ -typedef void *en50221_app_smartcard; +struct en50221_app_smartcard; /** * Create an instance of the smartcard resource. @@ -102,14 +109,15 @@ typedef void *en50221_app_smartcard; * @param funcs Send functions to use. * @return Instance, or NULL on failure. */ -extern en50221_app_smartcard en50221_app_smartcard_create(struct en50221_app_send_functions *funcs); +extern struct en50221_app_smartcard * + en50221_app_smartcard_create(struct en50221_app_send_functions *funcs); /** * Destroy an instance of the smartcard resource. * * @param smartcard Instance to destroy. */ -extern void en50221_app_smartcard_destroy(en50221_app_smartcard smartcard); +extern void en50221_app_smartcard_destroy(struct en50221_app_smartcard *smartcard); /** * Register the callback for when we receive a comms command. @@ -118,8 +126,9 @@ extern void en50221_app_smartcard_destroy(en50221_app_smartcard smartcard); * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_app_smartcard_register_command_callback(en50221_app_smartcard smartcard, - en50221_app_smartcard_command_callback callback, void *arg); +extern void en50221_app_smartcard_register_command_callback(struct en50221_app_smartcard *smartcard, + en50221_app_smartcard_command_callback callback, + void *arg); /** * Register the callback for when we receive data to send. @@ -128,8 +137,9 @@ extern void en50221_app_smartcard_register_command_callback(en50221_app_smartcar * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_app_smartcard_register_send_callback(en50221_app_smartcard smartcard, - en50221_app_smartcard_send_callback callback, void *arg); +extern void en50221_app_smartcard_register_send_callback(struct en50221_app_smartcard *smartcard, + en50221_app_smartcard_send_callback callback, + void *arg); /** * Send a command response to the CAM. @@ -142,12 +152,12 @@ extern void en50221_app_smartcard_register_send_callback(en50221_app_smartcard s * @param data_length Length of data to send. * @return 0 on success, -1 on failure. */ -extern int en50221_app_smartcard_command_reply(en50221_app_smartcard smartcard, - uint16_t session_number, - uint8_t reply_id, - uint8_t status, - uint8_t *data, - uint32_t data_length); +extern int en50221_app_smartcard_command_reply(struct en50221_app_smartcard *smartcard, + uint16_t session_number, + uint8_t reply_id, + uint8_t status, + uint8_t * data, + uint32_t data_length); /** * Send data received from a smartcart to the CAM. @@ -160,12 +170,11 @@ extern int en50221_app_smartcard_command_reply(en50221_app_smartcard smartcard, * @param SW2 SW2 value. * @return 0 on success, -1 on failure. */ -extern int en50221_app_smartcard_receive(en50221_app_smartcard smartcard, - uint16_t session_number, - uint8_t *data, - uint32_t data_length, - uint8_t SW1, - uint8_t SW2); +extern int en50221_app_smartcard_receive(struct en50221_app_smartcard *smartcard, + uint16_t session_number, + uint8_t * data, + uint32_t data_length, + uint8_t SW1, uint8_t SW2); /** * Pass data received for this resource into it for parsing. @@ -178,14 +187,14 @@ extern int en50221_app_smartcard_receive(en50221_app_smartcard smartcard, * @param data_length Length of data in bytes. * @return 0 on success, -1 on failure. */ -extern int en50221_app_smartcard_message(en50221_app_smartcard smartcard, - uint8_t slot_id, - uint16_t session_number, - uint32_t resource_id, - uint8_t *data, uint32_t data_length); +extern int en50221_app_smartcard_message(struct en50221_app_smartcard *smartcard, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t * data, + uint32_t data_length); #ifdef __cplusplus } #endif - #endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_tags.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_tags.h index 357999b..0f5c2fc 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_tags.h +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_tags.h @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) This library is free software; you can redistribute it and/or modify @@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __EN50221_APP_TAGS_H__ @@ -25,7 +25,7 @@ /* Resource Manager */ #define TAG_PROFILE_ENQUIRY 0x9f8010 -#define TAG_PROFILE 0x9f8011 +#define TAG_PROFILE 0x9f8011 #define TAG_PROFILE_CHANGE 0x9f8012 /* Application Info */ @@ -85,20 +85,20 @@ #define TAG_COMMS_RECV_MORE 0x9f8c06 /* Authentication */ -#define TAG_AUTH_REQ 0x9f8200 -#define TAG_AUTH_RESP 0x9f8201 +#define TAG_AUTH_REQ 0x9f8200 +#define TAG_AUTH_RESP 0x9f8201 /* Teletext */ -#define TAG_TELETEXT_EBU 0x9f9000 +#define TAG_TELETEXT_EBU 0x9f9000 /* Smartcard */ -#define TAG_SMARTCARD_COMMAND 0x9f8e00 -#define TAG_SMARTCARD_REPLY 0x9f8e01 -#define TAG_SMARTCARD_SEND 0x9f8e02 -#define TAG_SMARTCARD_RCV 0x9f8e03 +#define TAG_SMARTCARD_COMMAND 0x9f8e00 +#define TAG_SMARTCARD_REPLY 0x9f8e01 +#define TAG_SMARTCARD_SEND 0x9f8e02 +#define TAG_SMARTCARD_RCV 0x9f8e03 /* EPG */ -#define TAG_EPG_ENQUIRY 0x9f8f00 -#define TAG_EPG_REPLY 0x9f8f01 +#define TAG_EPG_ENQUIRY 0x9f8f00 +#define TAG_EPG_REPLY 0x9f8f01 #endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_teletext.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_teletext.c index 8e7f9d9..b839407 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_teletext.c +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_teletext.c @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,7 +18,7 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <string.h> @@ -28,112 +28,114 @@ #include "en50221_app_tags.h" #include "asn_1.h" -struct en50221_app_teletext_private { - struct en50221_app_send_functions *funcs; +struct en50221_app_teletext { + struct en50221_app_send_functions *funcs; - en50221_app_teletext_callback callback; - void *callback_arg; + en50221_app_teletext_callback callback; + void *callback_arg; - pthread_mutex_t lock; + pthread_mutex_t lock; }; -static int en50221_app_teletext_parse_ebu(struct en50221_app_teletext_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length); +static int en50221_app_teletext_parse_ebu(struct en50221_app_teletext *teletext, + uint8_t slot_id, + uint16_t session_number, + uint8_t * data, + uint32_t data_length); -en50221_app_teletext en50221_app_teletext_create(struct en50221_app_send_functions *funcs) +struct en50221_app_teletext * + en50221_app_teletext_create(struct en50221_app_send_functions *funcs) { - struct en50221_app_teletext_private *private = NULL; + struct en50221_app_teletext *teletext = NULL; - // create structure and set it up - private = malloc(sizeof(struct en50221_app_teletext_private)); - if (private == NULL) { - return NULL; - } - private->funcs = funcs; - private->callback = NULL; + // create structure and set it up + teletext = malloc(sizeof(struct en50221_app_teletext)); + if (teletext == NULL) { + return NULL; + } + teletext->funcs = funcs; + teletext->callback = NULL; - pthread_mutex_init(&private->lock, NULL); + pthread_mutex_init(&teletext->lock, NULL); - // done - return private; + // done + return teletext; } -void en50221_app_teletext_destroy(en50221_app_teletext teletext) +void en50221_app_teletext_destroy(struct en50221_app_teletext *teletext) { - struct en50221_app_teletext_private *private = (struct en50221_app_teletext_private *) teletext; - - pthread_mutex_destroy(&private->lock); - free(private); + pthread_mutex_destroy(&teletext->lock); + free(teletext); } -void en50221_app_teletext_register_callback(en50221_app_teletext teletext, - en50221_app_teletext_callback callback, void *arg) +void en50221_app_teletext_register_callback(struct en50221_app_teletext *teletext, + en50221_app_teletext_callback callback, void *arg) { - struct en50221_app_teletext_private *private = (struct en50221_app_teletext_private *) teletext; - - pthread_mutex_lock(&private->lock); - private->callback = callback; - private->callback_arg = arg; - pthread_mutex_unlock(&private->lock); + pthread_mutex_lock(&teletext->lock); + teletext->callback = callback; + teletext->callback_arg = arg; + pthread_mutex_unlock(&teletext->lock); } -int en50221_app_teletext_message(en50221_app_teletext teletext, - uint8_t slot_id, - uint16_t session_number, - uint32_t resource_id, - uint8_t *data, uint32_t data_length) +int en50221_app_teletext_message(struct en50221_app_teletext *teletext, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t * data, uint32_t data_length) { - struct en50221_app_teletext_private *private = (struct en50221_app_teletext_private *) teletext; - (void) resource_id; - - // get the tag - if (data_length < 3) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; - - switch(tag) - { - case TAG_TELETEXT_EBU: - return en50221_app_teletext_parse_ebu(private, slot_id, session_number, data+3, data_length-3); - } - - print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); - return -1; + (void) resource_id; + + // get the tag + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2]; + + switch (tag) { + case TAG_TELETEXT_EBU: + return en50221_app_teletext_parse_ebu(teletext, slot_id, + session_number, + data + 3, + data_length - 3); + } + + print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag); + return -1; } -static int en50221_app_teletext_parse_ebu(struct en50221_app_teletext_private *private, - uint8_t slot_id, uint16_t session_number, - uint8_t *data, uint32_t data_length) +static int en50221_app_teletext_parse_ebu(struct en50221_app_teletext *teletext, + uint8_t slot_id, + uint16_t session_number, + uint8_t *data, + uint32_t data_length) { - // first of all, decode the length field - uint16_t asn_data_length; - int length_field_len; - if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { - print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); - return -1; - } - - // check it - if (asn_data_length > (data_length-length_field_len)) { - print(LOG_LEVEL, ERROR, 1, "Received short data\n"); - return -1; - } - uint8_t *teletext_data = data + length_field_len; - - // tell the app - pthread_mutex_lock(&private->lock); - en50221_app_teletext_callback cb = private->callback; - void *cb_arg = private->callback_arg; - pthread_mutex_unlock(&private->lock); - if (cb) { - return cb(cb_arg, slot_id, session_number, teletext_data, asn_data_length); - } - return 0; + // first of all, decode the length field + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) { + print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n"); + return -1; + } + + // check it + if (asn_data_length > (data_length - length_field_len)) { + print(LOG_LEVEL, ERROR, 1, "Received short data\n"); + return -1; + } + uint8_t *teletext_data = data + length_field_len; + + // tell the app + pthread_mutex_lock(&teletext->lock); + en50221_app_teletext_callback cb = teletext->callback; + void *cb_arg = teletext->callback_arg; + pthread_mutex_unlock(&teletext->lock); + if (cb) { + return cb(cb_arg, slot_id, session_number, teletext_data, + asn_data_length); + } + return 0; } - diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_teletext.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_teletext.h index 3dced66..b5b85f1 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_teletext.h +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_teletext.h @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,15 +18,14 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __EN50221_APPLICATION_teletext_H__ #define __EN50221_APPLICATION_teletext_H__ #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif #include <stdlib.h> @@ -46,14 +45,16 @@ extern "C" * @param teletext_data_lenghth Number of bytes. * @return 0 on success, -1 on failure. */ -typedef int (*en50221_app_teletext_callback)(void *arg, uint8_t slot_id, uint16_t session_number, - uint8_t *teletext_data, - uint32_t teletext_data_length); +typedef int (*en50221_app_teletext_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number, + uint8_t *teletext_data, + uint32_t teletext_data_length); /** * Opaque type representing a teletext resource. */ -typedef void *en50221_app_teletext; +struct en50221_app_teletext; /** * Create an instance of the teletext resource. @@ -61,14 +62,15 @@ typedef void *en50221_app_teletext; * @param funcs Send functions to use. * @return Instance, or NULL on failure. */ -extern en50221_app_teletext en50221_app_teletext_create(struct en50221_app_send_functions *funcs); +extern struct en50221_app_teletext * + en50221_app_teletext_create(struct en50221_app_send_functions *funcs); /** * Destroy an instance of the teletext resource. * * @param teletext Instance to destroy. */ -extern void en50221_app_teletext_destroy(en50221_app_teletext teletext); +extern void en50221_app_teletext_destroy(struct en50221_app_teletext *teletext); /** * Register the callback for when we receive a request. @@ -77,8 +79,9 @@ extern void en50221_app_teletext_destroy(en50221_app_teletext teletext); * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_app_teletext_register_callback(en50221_app_teletext teletext, - en50221_app_teletext_callback callback, void *arg); +extern void en50221_app_teletext_register_callback(struct en50221_app_teletext *teletext, + en50221_app_teletext_callback callback, + void *arg); /** * Pass data received for this resource into it for parsing. @@ -91,14 +94,14 @@ extern void en50221_app_teletext_register_callback(en50221_app_teletext teletext * @param data_length Length of data in bytes. * @return 0 on success, -1 on failure. */ -extern int en50221_app_teletext_message(en50221_app_teletext teletext, - uint8_t slot_id, - uint16_t session_number, - uint32_t resource_id, - uint8_t *data, uint32_t data_length); +extern int en50221_app_teletext_message(struct en50221_app_teletext *teletext, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t * data, + uint32_t data_length); #ifdef __cplusplus } #endif - #endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_utils.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_utils.c index cbbbe2e..df2632a 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_utils.c +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_utils.c @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,20 +18,21 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "en50221_app_utils.h" -struct en50221_app_public_resource_id * - en50221_app_decode_public_resource_id(struct en50221_app_public_resource_id *idf, uint32_t resource_id) +struct en50221_app_public_resource_id + *en50221_app_decode_public_resource_id(struct en50221_app_public_resource_id *idf, + uint32_t resource_id) { - // reject private resources - if ((resource_id & 0xc0000000) == 0xc0000000) - return NULL; + // reject private resources + if ((resource_id & 0xc0000000) == 0xc0000000) + return NULL; - idf->resource_class = (resource_id >> 16) & 0xffff; // use the resource_id as the MSBs of class - idf->resource_type = (resource_id >> 6) & 0x3ff; - idf->resource_version = resource_id & 0x3f; - return idf; + idf->resource_class = (resource_id >> 16) & 0xffff; // use the resource_id as the MSBs of class + idf->resource_type = (resource_id >> 6) & 0x3ff; + idf->resource_version = resource_id & 0x3f; + return idf; } diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_utils.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_utils.h index d20c13b..5c64760 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_utils.h +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_utils.h @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,15 +18,14 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __EN50221_APP_UTILS_H__ #define __EN50221_APP_UTILS_H__ #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif #include <stdlib.h> @@ -41,30 +40,39 @@ extern "C" * would need special code for any private resource anyway. */ struct en50221_app_public_resource_id { - uint16_t resource_class; - uint16_t resource_type; - uint8_t resource_version; + uint16_t resource_class; + uint16_t resource_type; + uint8_t resource_version; }; +typedef int (*en50221_send_data) (void *arg, + uint16_t session_number, + uint8_t * data, + uint16_t data_length); +typedef int (*en50221_send_datav) (void *arg, + uint16_t session_number, + struct iovec * vector, + int iov_count); + /** * An abstraction away from hardcoded send functions so different layers may be * slotted in under the application layer. */ struct en50221_app_send_functions { - /** - * Argument to pass to these functions. - */ - void *arg; - - /** - * Send data. - */ - int (*send_data)(void *arg, uint16_t session_number, uint8_t *data, uint16_t data_length); - - /** - * Send vector data. - */ - int (*send_datav)(void *arg, uint16_t session_number, struct iovec *vector, int iov_count); + /** + * Argument to pass to these functions. + */ + void *arg; + + /** + * Send data. + */ + en50221_send_data send_data; + + /** + * Send vector data. + */ + en50221_send_datav send_datav; }; /** @@ -85,7 +93,8 @@ struct en50221_app_send_functions { * @return Pointer to idf on success, or NULL if this is not a public resource. */ struct en50221_app_public_resource_id * - en50221_app_decode_public_resource_id(struct en50221_app_public_resource_id *idf, uint32_t resource_id); + en50221_app_decode_public_resource_id(struct en50221_app_public_resource_id *idf, + uint32_t resource_id); /** * Encode an en50221_app_public_resource_id structure into a host-endian uint32_t. @@ -93,13 +102,11 @@ struct en50221_app_public_resource_id * * @param idf Structure to encode. * @return The encoded value */ -static inline uint32_t en50221_app_encode_public_resource_id(struct en50221_app_public_resource_id *idf) -{ - return MKRID(idf->resource_class, idf->resource_type, idf->resource_version); +static inline uint32_t en50221_app_encode_public_resource_id(struct en50221_app_public_resource_id *idf) { + return MKRID(idf->resource_class, idf->resource_type, idf->resource_version); } #ifdef __cplusplus } #endif - #endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_errno.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_errno.h index 5ac57fe..0b53087 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_errno.h +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_errno.h @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 session layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,35 +18,32 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef EN50221_ERRNO #define EN50221_ERRNO 1 #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif -#define EN50221ERR_CAREAD -1 /* error during read from CA device. */ -#define EN50221ERR_CAWRITE -2 /* error during write to CA device. */ -#define EN50221ERR_TIMEOUT -3 /* timeout occured waiting for a response from a device. */ -#define EN50221ERR_BADSLOTID -4 /* bad slot ID supplied by user - the offending slot_id will not be set. */ -#define EN50221ERR_BADCONNECTIONID -5 /* bad connection ID supplied by user. */ -#define EN50221ERR_BADSTATE -6 /* slot/connection in the wrong state. */ -#define EN50221ERR_BADCAMDATA -7 /* CAM supplied an invalid request. */ -#define EN50221ERR_OUTOFMEMORY -8 /* memory allocation failed. */ -#define EN50221ERR_ASNENCODE -9 /* ASN.1 encode failure - indicates library bug. */ -#define EN50221ERR_OUTOFCONNECTIONS -10 /* no more connections available. */ -#define EN50221ERR_OUTOFSLOTS -11 /* no more slots available - the offending slot_id will not be set. */ -#define EN50221ERR_IOVLIMIT -12 /* Too many struct iovecs were used. */ -#define EN50221ERR_BADSESSIONNUMBER -13 /* Bad session number suppplied by user. */ -#define EN50221ERR_OUTOFSESSIONS -14 /* no more sessions available. */ +#define EN50221ERR_CAREAD -1 /* error during read from CA device. */ +#define EN50221ERR_CAWRITE -2 /* error during write to CA device. */ +#define EN50221ERR_TIMEOUT -3 /* timeout occured waiting for a response from a device. */ +#define EN50221ERR_BADSLOTID -4 /* bad slot ID supplied by user - the offending slot_id will not be set. */ +#define EN50221ERR_BADCONNECTIONID -5 /* bad connection ID supplied by user. */ +#define EN50221ERR_BADSTATE -6 /* slot/connection in the wrong state. */ +#define EN50221ERR_BADCAMDATA -7 /* CAM supplied an invalid request. */ +#define EN50221ERR_OUTOFMEMORY -8 /* memory allocation failed. */ +#define EN50221ERR_ASNENCODE -9 /* ASN.1 encode failure - indicates library bug. */ +#define EN50221ERR_OUTOFCONNECTIONS -10 /* no more connections available. */ +#define EN50221ERR_OUTOFSLOTS -11 /* no more slots available - the offending slot_id will not be set. */ +#define EN50221ERR_IOVLIMIT -12 /* Too many struct iovecs were used. */ +#define EN50221ERR_BADSESSIONNUMBER -13 /* Bad session number suppplied by user. */ +#define EN50221ERR_OUTOFSESSIONS -14 /* no more sessions available. */ #ifdef __cplusplus } #endif - #endif - diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_session.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_session.c index 15cd52a..3fb9902 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_session.c +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_session.c @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,7 +18,7 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <stdio.h> @@ -37,918 +37,1019 @@ // these are the possible session statuses -#define S_STATUS_OPEN 0x00 // session is opened -#define S_STATUS_CLOSE_NO_RES 0xF0 // could not open session, no proper resource available -#define S_STATUS_CLOSE_RES_UNAVAILABLE 0xF1 // could not open session, resource unavailable -#define S_STATUS_CLOSE_RES_LOW_VERSION 0xF2 // could not open session, resource version too low -#define S_STATUS_CLOSE_RES_BUSY 0xF3 // could not open session, resource is busy - -#define ST_OPEN_SESSION_REQ 0x91 // h<--m -#define ST_OPEN_SESSION_RES 0x92 // h-->m -#define ST_CREATE_SESSION 0x93 // h-->m -#define ST_CREATE_SESSION_RES 0x94 // h<--m -#define ST_CLOSE_SESSION_REQ 0x95 // h<->m -#define ST_CLOSE_SESSION_RES 0x96 // h<->m -#define ST_SESSION_NUMBER 0x90 // h<->m - -#define S_STATE_IDLE 0x01 // this session is not in use -#define S_STATE_ACTIVE 0x02 // this session is in use -#define S_STATE_IN_CREATION 0x04 // this session waits for a ST_CREATE_SESSION_RES to become active -#define S_STATE_IN_DELETION 0x08 // this session waits for ST_CLOSE_SESSION_RES to become idle again +#define S_STATUS_OPEN 0x00 // session is opened +#define S_STATUS_CLOSE_NO_RES 0xF0 // could not open session, no proper resource available +#define S_STATUS_CLOSE_RES_UNAVAILABLE 0xF1 // could not open session, resource unavailable +#define S_STATUS_CLOSE_RES_LOW_VERSION 0xF2 // could not open session, resource version too low +#define S_STATUS_CLOSE_RES_BUSY 0xF3 // could not open session, resource is busy + +#define ST_OPEN_SESSION_REQ 0x91 // h<--m +#define ST_OPEN_SESSION_RES 0x92 // h-->m +#define ST_CREATE_SESSION 0x93 // h-->m +#define ST_CREATE_SESSION_RES 0x94 // h<--m +#define ST_CLOSE_SESSION_REQ 0x95 // h<->m +#define ST_CLOSE_SESSION_RES 0x96 // h<->m +#define ST_SESSION_NUMBER 0x90 // h<->m + +#define S_STATE_IDLE 0x01 // this session is not in use +#define S_STATE_ACTIVE 0x02 // this session is in use +#define S_STATE_IN_CREATION 0x04 // this session waits for a ST_CREATE_SESSION_RES to become active +#define S_STATE_IN_DELETION 0x08 // this session waits for ST_CLOSE_SESSION_RES to become idle again // for each session we store its identifier, the resource-id // it is linked to and the callback of the specific resource struct en50221_session { - uint8_t state; - uint32_t resource_id; - uint8_t slot_id; - uint8_t connection_id; + uint8_t state; + uint32_t resource_id; + uint8_t slot_id; + uint8_t connection_id; - en50221_sl_resource_callback callback; - void *callback_arg; + en50221_sl_resource_callback callback; + void *callback_arg; - pthread_mutex_t session_lock; + pthread_mutex_t session_lock; }; -struct en50221_session_layer_private -{ - uint32_t max_sessions; - en50221_transport_layer tl; +struct en50221_session_layer { + uint32_t max_sessions; + struct en50221_transport_layer *tl; - en50221_sl_lookup_callback lookup; - void *lookup_arg; + en50221_sl_lookup_callback lookup; + void *lookup_arg; - en50221_sl_session_callback session; - void *session_arg; + en50221_sl_session_callback session; + void *session_arg; - pthread_mutex_t global_lock; - pthread_mutex_t setcallback_lock; + pthread_mutex_t global_lock; + pthread_mutex_t setcallback_lock; - int error; + int error; - struct en50221_session *sessions; + struct en50221_session *sessions; }; -static void en50221_sl_transport_callback(void *arg, int reason, uint8_t *data, uint32_t data_length, - uint8_t slot_id, uint8_t connection_id); -static int en50221_sl_alloc_new_session(struct en50221_session_layer_private *private, - uint32_t resource_id, - uint8_t slot_id, - uint8_t connection_id, - en50221_sl_resource_callback callback, void* arg); +static void en50221_sl_transport_callback(void *arg, int reason, + uint8_t * data, + uint32_t data_length, + uint8_t slot_id, + uint8_t connection_id); +static int en50221_sl_alloc_new_session(struct en50221_session_layer *sl, + uint32_t resource_id, + uint8_t slot_id, + uint8_t connection_id, + en50221_sl_resource_callback + callback, void *arg); -en50221_session_layer en50221_sl_create(en50221_transport_layer tl, - uint32_t max_sessions) +struct en50221_session_layer *en50221_sl_create(struct en50221_transport_layer *tl, + uint32_t max_sessions) { - struct en50221_session_layer_private *private = NULL; - uint32_t i; - - // setup structure - private = (struct en50221_session_layer_private*) malloc(sizeof(struct en50221_session_layer_private)); - if (private == NULL) - goto error_exit; - private->max_sessions = max_sessions; - private->lookup = NULL; - private->session = NULL; - private->tl = tl; - private->error = 0; - - // init the mutex - pthread_mutex_init(&private->global_lock, NULL); - pthread_mutex_init(&private->setcallback_lock, NULL); - - // create the slots - private->sessions = malloc(sizeof(struct en50221_session) * max_sessions); - if (private->sessions == NULL) - goto error_exit; - - // set them up - for(i=0; i< max_sessions; i++) { - private->sessions[i].state = S_STATE_IDLE; - private->sessions[i].callback = NULL; - - pthread_mutex_init(&private->sessions[i].session_lock, NULL); - } - - // register ourselves with the transport layer - en50221_tl_register_callback(tl, en50221_sl_transport_callback, private); - - return private; + struct en50221_session_layer *sl = NULL; + uint32_t i; + + // setup structure + sl = (struct en50221_session_layer *) + malloc(sizeof(struct en50221_session_layer)); + if (sl == NULL) + goto error_exit; + sl->max_sessions = max_sessions; + sl->lookup = NULL; + sl->session = NULL; + sl->tl = tl; + sl->error = 0; + + // init the mutex + pthread_mutex_init(&sl->global_lock, NULL); + pthread_mutex_init(&sl->setcallback_lock, NULL); + + // create the slots + sl->sessions = malloc(sizeof(struct en50221_session) * max_sessions); + if (sl->sessions == NULL) + goto error_exit; + + // set them up + for (i = 0; i < max_sessions; i++) { + sl->sessions[i].state = S_STATE_IDLE; + sl->sessions[i].callback = NULL; + + pthread_mutex_init(&sl->sessions[i].session_lock, NULL); + } + + // register ourselves with the transport layer + en50221_tl_register_callback(tl, en50221_sl_transport_callback, sl); + + return sl; error_exit: - en50221_sl_destroy(private); - return NULL; + en50221_sl_destroy(sl); + return NULL; } -void en50221_sl_destroy(en50221_session_layer sl) +void en50221_sl_destroy(struct en50221_session_layer *sl) { - struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) sl; - uint32_t i; - - if (private) { - if (private->sessions) { - for(i=0; i< private->max_sessions; i++) { - pthread_mutex_destroy(&private->sessions[i].session_lock); - } - free(private->sessions); - } - - pthread_mutex_destroy(&private->setcallback_lock); - pthread_mutex_destroy(&private->global_lock); - - free(private); - } + uint32_t i; + + if (sl) { + if (sl->sessions) { + for (i = 0; i < sl->max_sessions; i++) { + pthread_mutex_destroy(&sl->sessions[i].session_lock); + } + free(sl->sessions); + } + + pthread_mutex_destroy(&sl->setcallback_lock); + pthread_mutex_destroy(&sl->global_lock); + + free(sl); + } } -int en50221_sl_get_error(en50221_session_layer tl) +int en50221_sl_get_error(struct en50221_session_layer *sl) { - struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) tl; - return private->error; + return sl->error; } -void en50221_sl_register_lookup_callback(en50221_session_layer sl, en50221_sl_lookup_callback callback, void *arg) +void en50221_sl_register_lookup_callback(struct en50221_session_layer *sl, + en50221_sl_lookup_callback + callback, void *arg) { - struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) sl; - - pthread_mutex_lock(&private->setcallback_lock); - private->lookup = callback; - private->lookup_arg = arg; - pthread_mutex_unlock(&private->setcallback_lock); + pthread_mutex_lock(&sl->setcallback_lock); + sl->lookup = callback; + sl->lookup_arg = arg; + pthread_mutex_unlock(&sl->setcallback_lock); } -void en50221_sl_register_session_callback(en50221_session_layer sl, - en50221_sl_session_callback callback, void *arg) +void en50221_sl_register_session_callback(struct en50221_session_layer *sl, + en50221_sl_session_callback + callback, void *arg) { - struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) sl; - - pthread_mutex_lock(&private->setcallback_lock); - private->session = callback; - private->session_arg = arg; - pthread_mutex_unlock(&private->setcallback_lock); + pthread_mutex_lock(&sl->setcallback_lock); + sl->session = callback; + sl->session_arg = arg; + pthread_mutex_unlock(&sl->setcallback_lock); } -int en50221_sl_create_session(en50221_session_layer sl, int slot_id, uint8_t connection_id, uint32_t resource_id, - en50221_sl_resource_callback callback, void* arg) +int en50221_sl_create_session(struct en50221_session_layer *sl, + int slot_id, uint8_t connection_id, + uint32_t resource_id, + en50221_sl_resource_callback callback, + void *arg) { - struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) sl; - - // lookup next free session_id: - pthread_mutex_lock(&private->global_lock); - int session_number = en50221_sl_alloc_new_session(private, resource_id, slot_id, connection_id, callback, arg); - if (session_number == -1) { - pthread_mutex_unlock(&private->global_lock); - return -1; - } - pthread_mutex_unlock(&private->global_lock); - - // make up the header - uint8_t hdr[8]; - hdr[0] = ST_CREATE_SESSION; - hdr[1] = 6; - hdr[2] = resource_id >> 24; - hdr[3] = resource_id >> 16; - hdr[4] = resource_id >> 8; - hdr[5] = resource_id; - hdr[6] = session_number >> 8; - hdr[7] = session_number; - - // send this command - if (en50221_tl_send_data(private->tl, slot_id, connection_id, hdr, 8)) { - pthread_mutex_lock(&private->sessions[session_number].session_lock); - if (private->sessions[session_number].state == S_STATE_IN_CREATION) { - private->sessions[session_number].state = S_STATE_IDLE; - } - pthread_mutex_unlock(&private->sessions[session_number].session_lock); - - private->error = en50221_tl_get_error(private->tl); - return -1; - } - - // ok. - return session_number; + // lookup next free session_id: + pthread_mutex_lock(&sl->global_lock); + int session_number = + en50221_sl_alloc_new_session(sl, resource_id, slot_id, + connection_id, callback, arg); + if (session_number == -1) { + pthread_mutex_unlock(&sl->global_lock); + return -1; + } + pthread_mutex_unlock(&sl->global_lock); + + // make up the header + uint8_t hdr[8]; + hdr[0] = ST_CREATE_SESSION; + hdr[1] = 6; + hdr[2] = resource_id >> 24; + hdr[3] = resource_id >> 16; + hdr[4] = resource_id >> 8; + hdr[5] = resource_id; + hdr[6] = session_number >> 8; + hdr[7] = session_number; + + // send this command + if (en50221_tl_send_data(sl->tl, slot_id, connection_id, hdr, 8)) { + pthread_mutex_lock(&sl->sessions[session_number].session_lock); + if (sl->sessions[session_number].state == S_STATE_IN_CREATION) { + sl->sessions[session_number].state = S_STATE_IDLE; + } + pthread_mutex_unlock(&sl->sessions[session_number].session_lock); + + sl->error = en50221_tl_get_error(sl->tl); + return -1; + } + // ok. + return session_number; } -int en50221_sl_destroy_session(en50221_session_layer sl, uint16_t session_number) +int en50221_sl_destroy_session(struct en50221_session_layer *sl, + uint16_t session_number) { - struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) sl; - - if (session_number >= private->max_sessions) { - private->error = EN50221ERR_BADSESSIONNUMBER; - return -1; - } - - pthread_mutex_lock(&private->sessions[session_number].session_lock); - if (!(private->sessions[session_number].state & (S_STATE_ACTIVE|S_STATE_IN_DELETION))) { - private->error = EN50221ERR_BADSESSIONNUMBER; - pthread_mutex_unlock(&private->sessions[session_number].session_lock); - return -1; - } - - // set the state - private->sessions[session_number].state = S_STATE_IN_DELETION; - - // get essential details - uint8_t slot_id = private->sessions[session_number].slot_id; - uint8_t connection_id = private->sessions[session_number].connection_id; - pthread_mutex_unlock(&private->sessions[session_number].session_lock); - - // sendit - uint8_t hdr[4]; - hdr[0] = ST_CLOSE_SESSION_REQ; - hdr[1] = 2; - hdr[2] = session_number >> 8; - hdr[3] = session_number; - if (en50221_tl_send_data(private->tl, slot_id, connection_id, hdr, 4)) { - pthread_mutex_lock(&private->sessions[session_number].session_lock); - if (private->sessions[session_number].state == S_STATE_IN_DELETION) { - private->sessions[session_number].state = S_STATE_IDLE; - } - pthread_mutex_unlock(&private->sessions[session_number].session_lock); - - private->error = en50221_tl_get_error(private->tl); - return -1; - } - - return 0; + if (session_number >= sl->max_sessions) { + sl->error = EN50221ERR_BADSESSIONNUMBER; + return -1; + } + + pthread_mutex_lock(&sl->sessions[session_number].session_lock); + if (!(sl->sessions[session_number].state & (S_STATE_ACTIVE | S_STATE_IN_DELETION))) { + sl->error = EN50221ERR_BADSESSIONNUMBER; + pthread_mutex_unlock(&sl->sessions[session_number].session_lock); + return -1; + } + // set the state + sl->sessions[session_number].state = S_STATE_IN_DELETION; + + // get essential details + uint8_t slot_id = sl->sessions[session_number].slot_id; + uint8_t connection_id = sl->sessions[session_number].connection_id; + pthread_mutex_unlock(&sl->sessions[session_number].session_lock); + + // sendit + uint8_t hdr[4]; + hdr[0] = ST_CLOSE_SESSION_REQ; + hdr[1] = 2; + hdr[2] = session_number >> 8; + hdr[3] = session_number; + if (en50221_tl_send_data(sl->tl, slot_id, connection_id, hdr, 4)) { + pthread_mutex_lock(&sl->sessions[session_number].session_lock); + if (sl->sessions[session_number].state == S_STATE_IN_DELETION) { + sl->sessions[session_number].state = S_STATE_IDLE; + } + pthread_mutex_unlock(&sl->sessions[session_number].session_lock); + + sl->error = en50221_tl_get_error(sl->tl); + return -1; + } + + return 0; } -int en50221_sl_send_data(en50221_session_layer sl, uint16_t session_number, uint8_t *data, uint16_t data_length) +int en50221_sl_send_data(struct en50221_session_layer *sl, + uint16_t session_number, + uint8_t *data, + uint16_t data_length) { - struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) sl; - - if (session_number >= private->max_sessions) { - private->error = EN50221ERR_BADSESSIONNUMBER; - return -1; - } - - pthread_mutex_lock(&private->sessions[session_number].session_lock); - if (private->sessions[session_number].state != S_STATE_ACTIVE) { - private->error = EN50221ERR_BADSESSIONNUMBER; - pthread_mutex_unlock(&private->sessions[session_number].session_lock); - return -1; - } - - // get essential details - uint8_t slot_id = private->sessions[session_number].slot_id; - uint8_t connection_id = private->sessions[session_number].connection_id; - pthread_mutex_unlock(&private->sessions[session_number].session_lock); - - // sendit - struct iovec iov[2]; - uint8_t hdr[4]; - hdr[0] = ST_SESSION_NUMBER; - hdr[1] = 2; - hdr[2] = session_number >> 8; - hdr[3] = session_number; - iov[0].iov_base = hdr; - iov[0].iov_len = 4; - iov[1].iov_base = data; - iov[1].iov_len = data_length; - if (en50221_tl_send_datav(private->tl, slot_id, connection_id, iov, 2)) { - private->error = en50221_tl_get_error(private->tl); - return -1; - } - - return 0; + if (session_number >= sl->max_sessions) { + sl->error = EN50221ERR_BADSESSIONNUMBER; + return -1; + } + + pthread_mutex_lock(&sl->sessions[session_number].session_lock); + if (sl->sessions[session_number].state != S_STATE_ACTIVE) { + sl->error = EN50221ERR_BADSESSIONNUMBER; + pthread_mutex_unlock(&sl->sessions[session_number].session_lock); + return -1; + } + // get essential details + uint8_t slot_id = sl->sessions[session_number].slot_id; + uint8_t connection_id = sl->sessions[session_number].connection_id; + pthread_mutex_unlock(&sl->sessions[session_number].session_lock); + + // sendit + struct iovec iov[2]; + uint8_t hdr[4]; + hdr[0] = ST_SESSION_NUMBER; + hdr[1] = 2; + hdr[2] = session_number >> 8; + hdr[3] = session_number; + iov[0].iov_base = hdr; + iov[0].iov_len = 4; + iov[1].iov_base = data; + iov[1].iov_len = data_length; + if (en50221_tl_send_datav(sl->tl, slot_id, connection_id, iov, 2)) { + sl->error = en50221_tl_get_error(sl->tl); + return -1; + } + + return 0; } -int en50221_sl_send_datav(en50221_session_layer sl, uint16_t session_number, - struct iovec *vector, int iov_count) +int en50221_sl_send_datav(struct en50221_session_layer *sl, + uint16_t session_number, + struct iovec *vector, + int iov_count) { - struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) sl; - - if (session_number >= private->max_sessions) { - private->error = EN50221ERR_BADSESSIONNUMBER; - return -1; - } - - pthread_mutex_lock(&private->sessions[session_number].session_lock); - if (private->sessions[session_number].state != S_STATE_ACTIVE) { - private->error = EN50221ERR_BADSESSIONNUMBER; - pthread_mutex_unlock(&private->sessions[session_number].session_lock); - return -1; - } - if (iov_count > 9) { - private->error = EN50221ERR_IOVLIMIT; - pthread_mutex_unlock(&private->sessions[session_number].session_lock); - return -1; - } - uint8_t slot_id = private->sessions[session_number].slot_id; - uint8_t connection_id = private->sessions[session_number].connection_id; - pthread_mutex_unlock(&private->sessions[session_number].session_lock); - - // make up the header - struct iovec out_iov[10]; - uint8_t hdr[4]; - hdr[0] = ST_SESSION_NUMBER; - hdr[1] = 2; - hdr[2] = session_number >> 8; - hdr[3] = session_number; - out_iov[0].iov_base = hdr; - out_iov[0].iov_len = 4; - - // make up the data - memcpy(&out_iov[1], vector, iov_count * sizeof(struct iovec)); - - // send this command - if (en50221_tl_send_datav(private->tl, slot_id, connection_id, out_iov, iov_count+1)) { - private->error = en50221_tl_get_error(private->tl); - return -1; - } - return 0; + if (session_number >= sl->max_sessions) { + sl->error = EN50221ERR_BADSESSIONNUMBER; + return -1; + } + + pthread_mutex_lock(&sl->sessions[session_number].session_lock); + if (sl->sessions[session_number].state != S_STATE_ACTIVE) { + sl->error = EN50221ERR_BADSESSIONNUMBER; + pthread_mutex_unlock(&sl->sessions[session_number].session_lock); + return -1; + } + if (iov_count > 9) { + sl->error = EN50221ERR_IOVLIMIT; + pthread_mutex_unlock(&sl->sessions[session_number].session_lock); + return -1; + } + uint8_t slot_id = sl->sessions[session_number].slot_id; + uint8_t connection_id = sl->sessions[session_number].connection_id; + pthread_mutex_unlock(&sl->sessions[session_number].session_lock); + + // make up the header + struct iovec out_iov[10]; + uint8_t hdr[4]; + hdr[0] = ST_SESSION_NUMBER; + hdr[1] = 2; + hdr[2] = session_number >> 8; + hdr[3] = session_number; + out_iov[0].iov_base = hdr; + out_iov[0].iov_len = 4; + + // make up the data + memcpy(&out_iov[1], vector, iov_count * sizeof(struct iovec)); + + // send this command + if (en50221_tl_send_datav(sl->tl, slot_id, connection_id, out_iov, iov_count + 1)) { + sl->error = en50221_tl_get_error(sl->tl); + return -1; + } + return 0; } -int en50221_sl_broadcast_data(en50221_session_layer sl, int slot_id, uint32_t resource_id, - uint8_t *data, uint16_t data_length) +int en50221_sl_broadcast_data(struct en50221_session_layer *sl, + int slot_id, uint32_t resource_id, + uint8_t *data, uint16_t data_length) { - struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) sl; - uint32_t i; - - for(i = 0; i < private->max_sessions; i++) - { - pthread_mutex_lock(&private->sessions[i].session_lock); - - if (private->sessions[i].state != S_STATE_ACTIVE) { - pthread_mutex_unlock(&private->sessions[i].session_lock); - continue; - } - if ((slot_id != -1) && (slot_id != private->sessions[i].slot_id)) { - pthread_mutex_unlock(&private->sessions[i].session_lock); - continue; - } - - if (private->sessions[i].resource_id == resource_id) { - pthread_mutex_unlock(&private->sessions[i].session_lock); - en50221_sl_send_data(sl, i, data, data_length); - } else { - pthread_mutex_unlock(&private->sessions[i].session_lock); - } - } - - return 0; + uint32_t i; + + for (i = 0; i < sl->max_sessions; i++) { + pthread_mutex_lock(&sl->sessions[i].session_lock); + + if (sl->sessions[i].state != S_STATE_ACTIVE) { + pthread_mutex_unlock(&sl->sessions[i].session_lock); + continue; + } + if ((slot_id != -1) + && (slot_id != sl->sessions[i].slot_id)) { + pthread_mutex_unlock(&sl->sessions[i].session_lock); + continue; + } + + if (sl->sessions[i].resource_id == resource_id) { + pthread_mutex_unlock(&sl->sessions[i].session_lock); + en50221_sl_send_data(sl, i, data, data_length); + } else { + pthread_mutex_unlock(&sl->sessions[i].session_lock); + } + } + + return 0; } -static void en50221_sl_handle_open_session_request(struct en50221_session_layer_private *private, - uint8_t *data, uint32_t data_length, uint8_t slot_id, uint8_t connection_id) +static void en50221_sl_handle_open_session_request(struct en50221_session_layer *sl, + uint8_t *data, + uint32_t data_length, + uint8_t slot_id, + uint8_t connection_id) { - // check - if (data_length < 5) { - print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id); - return; - } - if (data[0] != 4) { - print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id); - return; - } - - // get the resource id - uint32_t requested_resource_id = (data[1] << 24) | (data[2] << 16) | (data[3] << 8) | data[4]; - - // get lookup callback details - pthread_mutex_lock(&private->setcallback_lock); - en50221_sl_lookup_callback lcb = private->lookup; - void *lcb_arg = private->lookup_arg; - pthread_mutex_unlock(&private->setcallback_lock); - - // first of all, lookup this resource id - int status = S_STATUS_CLOSE_NO_RES; - en50221_sl_resource_callback resource_callback = NULL; - void *resource_arg = NULL; - uint32_t connected_resource_id; - if (lcb) { - status = lcb(lcb_arg, slot_id, requested_resource_id, &resource_callback, &resource_arg, &connected_resource_id); - switch(status) { - case 0: - status = S_STATUS_OPEN; - break; - - case -1: - status = S_STATUS_CLOSE_NO_RES; - break; - - case -2: - status = S_STATUS_CLOSE_RES_LOW_VERSION; - break; - - case -3: - status = S_STATUS_CLOSE_RES_UNAVAILABLE; - break; - } - } - - // if we found it, get a new session for it - int session_number = -1; - if (status == S_STATUS_OPEN) { - // lookup next free session_id: - pthread_mutex_lock(&private->global_lock); - session_number = en50221_sl_alloc_new_session(private, connected_resource_id, slot_id, connection_id, - resource_callback, resource_arg); - pthread_mutex_unlock(&private->global_lock); - - if (session_number == -1) { - status = S_STATUS_CLOSE_NO_RES; - } else { - // inform upper layers/ check availability - pthread_mutex_lock(&private->setcallback_lock); - en50221_sl_session_callback cb = private->session; - void *cb_arg = private->session_arg; - pthread_mutex_unlock(&private->setcallback_lock); - if (cb) { - if (cb(cb_arg, S_SCALLBACK_REASON_CAMCONNECTING, slot_id, session_number, connected_resource_id)) { - status = S_STATUS_CLOSE_RES_BUSY; - } - } else { - status = S_STATUS_CLOSE_RES_UNAVAILABLE; - } - } - } - - // send response - uint8_t hdr[9]; - hdr[0] = ST_OPEN_SESSION_RES; - hdr[1] = 7; - hdr[2] = status; - hdr[3] = connected_resource_id >> 24; - hdr[4] = connected_resource_id >> 16; - hdr[5] = connected_resource_id >> 8; - hdr[6] = connected_resource_id; - hdr[7] = session_number >> 8; - hdr[8] = session_number; - if (en50221_tl_send_data(private->tl, slot_id, connection_id, hdr, 9)) { - print(LOG_LEVEL, ERROR, 1, "Transport layer error %i occurred\n", en50221_tl_get_error(private->tl)); - status = S_STATUS_CLOSE_NO_RES; - // fallthrough - } - - // inform upper layers what happened - if (session_number != -1) { - // setup session state apppropriately from upper layer response - pthread_mutex_lock(&private->sessions[session_number].session_lock); - if (status != S_STATUS_OPEN) { - private->sessions[session_number].state = S_STATE_IDLE; - } else { - private->sessions[session_number].state = S_STATE_ACTIVE; - } - pthread_mutex_unlock(&private->sessions[session_number].session_lock); - - // tell upper layers - if (private->sessions[session_number].state == S_STATE_ACTIVE) { - pthread_mutex_lock(&private->setcallback_lock); - en50221_sl_session_callback cb = private->session; - void *cb_arg = private->session_arg; - pthread_mutex_unlock(&private->setcallback_lock); - - if (status == S_STATUS_OPEN) { - if (cb) - cb(cb_arg, S_SCALLBACK_REASON_CAMCONNECTED, slot_id, session_number, connected_resource_id); - } else { - private->sessions[session_number].state = S_STATE_IDLE; - if (cb) - cb(cb_arg, S_SCALLBACK_REASON_CAMCONNECTFAIL, slot_id, session_number, connected_resource_id); - } - } - } + // check + if (data_length < 5) { + print(LOG_LEVEL, ERROR, 1, + "Received data with invalid length from module on slot %02x\n", + slot_id); + return; + } + if (data[0] != 4) { + print(LOG_LEVEL, ERROR, 1, + "Received data with invalid length from module on slot %02x\n", + slot_id); + return; + } + // get the resource id + uint32_t requested_resource_id = + (data[1] << 24) | (data[2] << 16) | (data[3] << 8) | data[4]; + + // get lookup callback details + pthread_mutex_lock(&sl->setcallback_lock); + en50221_sl_lookup_callback lcb = sl->lookup; + void *lcb_arg = sl->lookup_arg; + pthread_mutex_unlock(&sl->setcallback_lock); + + // first of all, lookup this resource id + int status = S_STATUS_CLOSE_NO_RES; + en50221_sl_resource_callback resource_callback = NULL; + void *resource_arg = NULL; + uint32_t connected_resource_id; + if (lcb) { + status = + lcb(lcb_arg, slot_id, requested_resource_id, + &resource_callback, &resource_arg, + &connected_resource_id); + switch (status) { + case 0: + status = S_STATUS_OPEN; + break; + + case -1: + status = S_STATUS_CLOSE_NO_RES; + break; + + case -2: + status = S_STATUS_CLOSE_RES_LOW_VERSION; + break; + + case -3: + status = S_STATUS_CLOSE_RES_UNAVAILABLE; + break; + } + } + // if we found it, get a new session for it + int session_number = -1; + if (status == S_STATUS_OPEN) { + // lookup next free session_id: + pthread_mutex_lock(&sl->global_lock); + session_number = + en50221_sl_alloc_new_session(sl, connected_resource_id, + slot_id, connection_id, + resource_callback, + resource_arg); + pthread_mutex_unlock(&sl->global_lock); + + if (session_number == -1) { + status = S_STATUS_CLOSE_NO_RES; + } else { + // inform upper layers/ check availability + pthread_mutex_lock(&sl->setcallback_lock); + en50221_sl_session_callback cb = sl->session; + void *cb_arg = sl->session_arg; + pthread_mutex_unlock(&sl->setcallback_lock); + if (cb) { + if (cb(cb_arg, S_SCALLBACK_REASON_CAMCONNECTING, + slot_id, session_number, + connected_resource_id)) { + status = S_STATUS_CLOSE_RES_BUSY; + } + } else { + status = S_STATUS_CLOSE_RES_UNAVAILABLE; + } + } + } + // send response + uint8_t hdr[9]; + hdr[0] = ST_OPEN_SESSION_RES; + hdr[1] = 7; + hdr[2] = status; + hdr[3] = connected_resource_id >> 24; + hdr[4] = connected_resource_id >> 16; + hdr[5] = connected_resource_id >> 8; + hdr[6] = connected_resource_id; + hdr[7] = session_number >> 8; + hdr[8] = session_number; + if (en50221_tl_send_data(sl->tl, slot_id, connection_id, hdr, 9)) { + print(LOG_LEVEL, ERROR, 1, + "Transport layer error %i occurred\n", + en50221_tl_get_error(sl->tl)); + status = S_STATUS_CLOSE_NO_RES; + // fallthrough + } + // inform upper layers what happened + if (session_number != -1) { + // setup session state apppropriately from upper layer response + pthread_mutex_lock(&sl->sessions[session_number].session_lock); + if (status != S_STATUS_OPEN) { + sl->sessions[session_number].state = S_STATE_IDLE; + } else { + sl->sessions[session_number].state = S_STATE_ACTIVE; + } + pthread_mutex_unlock(&sl->sessions[session_number].session_lock); + + // tell upper layers + if (sl->sessions[session_number].state == S_STATE_ACTIVE) { + pthread_mutex_lock(&sl->setcallback_lock); + en50221_sl_session_callback cb = sl->session; + void *cb_arg = sl->session_arg; + pthread_mutex_unlock(&sl->setcallback_lock); + + if (status == S_STATUS_OPEN) { + if (cb) + cb(cb_arg, + S_SCALLBACK_REASON_CAMCONNECTED, + slot_id, session_number, + connected_resource_id); + } else { + sl->sessions[session_number].state = + S_STATE_IDLE; + if (cb) + cb(cb_arg, + S_SCALLBACK_REASON_CAMCONNECTFAIL, + slot_id, session_number, + connected_resource_id); + } + } + } } -static void en50221_sl_handle_close_session_request(struct en50221_session_layer_private *private, - uint8_t *data, uint32_t data_length, uint8_t slot_id, uint8_t connection_id) +static void en50221_sl_handle_close_session_request(struct en50221_session_layer *sl, + uint8_t * data, + uint32_t data_length, + uint8_t slot_id, + uint8_t connection_id) { - // check - if (data_length < 3) { - print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id); - return; - } - if (data[0] != 2) { - print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id); - return; - } - - // extract session number - uint16_t session_number = (data[1] << 8) | data[2]; - - // check session number is ok - uint8_t code = 0x00; - uint32_t resource_id = 0; - if (session_number >= private->max_sessions) { - code = 0xF0; // session close error - print(LOG_LEVEL, ERROR, 1, "Received bad session id %i\n", slot_id); - } else { - pthread_mutex_lock(&private->sessions[session_number].session_lock); - if (slot_id != private->sessions[session_number].slot_id) { - print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id); - code = 0xF0; // session close error - } - if (connection_id != private->sessions[session_number].connection_id) { - print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id); - code = 0xF0; // session close error - } - if (!(private->sessions[session_number].state & (S_STATE_ACTIVE|S_STATE_IN_DELETION))) { - print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id); - code = 0xF0; // session close error - } - - if (code == 0x00) { - private->sessions[session_number].state = S_STATE_IDLE; - code = 0x00; // close ok - } - resource_id = private->sessions[session_number].resource_id; - pthread_mutex_unlock(&private->sessions[session_number].session_lock); - } - - // make up the response - uint8_t hdr[5]; - hdr[0] = ST_CLOSE_SESSION_RES; - hdr[1] = 3; - hdr[2] = code; - hdr[3] = session_number >> 8; - hdr[4] = session_number; - - // sendit - if (en50221_tl_send_data(private->tl, slot_id, connection_id, hdr, 5)) { - print(LOG_LEVEL, ERROR, 1, "Transport layer reports error %i on slot %i\n", - en50221_tl_get_error(private->tl), slot_id); - } - - // callback to announce destruction to resource if it was ok - if (code == 0x00) { - pthread_mutex_lock(&private->setcallback_lock); - en50221_sl_session_callback cb = private->session; - void *cb_arg = private->session_arg; - pthread_mutex_unlock(&private->setcallback_lock); - - if (cb) - cb(cb_arg, S_SCALLBACK_REASON_CLOSE, slot_id, session_number, resource_id); - } + // check + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, + "Received data with invalid length from module on slot %02x\n", + slot_id); + return; + } + if (data[0] != 2) { + print(LOG_LEVEL, ERROR, 1, + "Received data with invalid length from module on slot %02x\n", + slot_id); + return; + } + // extract session number + uint16_t session_number = (data[1] << 8) | data[2]; + + // check session number is ok + uint8_t code = 0x00; + uint32_t resource_id = 0; + if (session_number >= sl->max_sessions) { + code = 0xF0; // session close error + print(LOG_LEVEL, ERROR, 1, "Received bad session id %i\n", + slot_id); + } else { + pthread_mutex_lock(&sl->sessions[session_number]. + session_lock); + if (slot_id != sl->sessions[session_number].slot_id) { + print(LOG_LEVEL, ERROR, 1, + "Received unexpected session on invalid slot %i\n", + slot_id); + code = 0xF0; // session close error + } + if (connection_id != sl->sessions[session_number].connection_id) { + print(LOG_LEVEL, ERROR, 1, + "Received unexpected session on invalid slot %i\n", + slot_id); + code = 0xF0; // session close error + } + if (!(sl->sessions[session_number].state & (S_STATE_ACTIVE | S_STATE_IN_DELETION))) { + print(LOG_LEVEL, ERROR, 1, + "Received unexpected session on invalid slot %i\n", + slot_id); + code = 0xF0; // session close error + } + + if (code == 0x00) { + sl->sessions[session_number].state = S_STATE_IDLE; + code = 0x00; // close ok + } + resource_id = sl->sessions[session_number].resource_id; + pthread_mutex_unlock(&sl->sessions[session_number].session_lock); + } + + // make up the response + uint8_t hdr[5]; + hdr[0] = ST_CLOSE_SESSION_RES; + hdr[1] = 3; + hdr[2] = code; + hdr[3] = session_number >> 8; + hdr[4] = session_number; + + // sendit + if (en50221_tl_send_data(sl->tl, slot_id, connection_id, hdr, 5)) { + print(LOG_LEVEL, ERROR, 1, + "Transport layer reports error %i on slot %i\n", + en50221_tl_get_error(sl->tl), slot_id); + } + // callback to announce destruction to resource if it was ok + if (code == 0x00) { + pthread_mutex_lock(&sl->setcallback_lock); + en50221_sl_session_callback cb = sl->session; + void *cb_arg = sl->session_arg; + pthread_mutex_unlock(&sl->setcallback_lock); + + if (cb) + cb(cb_arg, S_SCALLBACK_REASON_CLOSE, slot_id, + session_number, resource_id); + } } -static void en50221_sl_handle_create_session_response(struct en50221_session_layer_private *private, - uint8_t *data, uint32_t data_length, uint8_t slot_id, uint8_t connection_id) +static void en50221_sl_handle_create_session_response(struct en50221_session_layer *sl, + uint8_t * data, + uint32_t data_length, + uint8_t slot_id, + uint8_t connection_id) { - // check - if (data_length < 8) { - print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id); - return; - } - if (data[0] != 7) { - print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id); - return; - } - - // extract session number - uint16_t session_number = (data[5] << 8) | data[6]; - - // check session number is ok - if (session_number >= private->max_sessions) { - print(LOG_LEVEL, ERROR, 1, "Received bad session id %i\n", slot_id); - return; - } - - pthread_mutex_lock(&private->sessions[session_number].session_lock); - if (slot_id != private->sessions[session_number].slot_id) { - print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id); - pthread_mutex_unlock(&private->sessions[session_number].session_lock); - return; - } - if (connection_id != private->sessions[session_number].connection_id) { - print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id); - pthread_mutex_unlock(&private->sessions[session_number].session_lock); - return; - } - if (private->sessions[session_number].state != S_STATE_IN_CREATION) { - print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id); - pthread_mutex_unlock(&private->sessions[session_number].session_lock); - return; - } - - // extract status - if (data[1] != S_STATUS_OPEN) { - print(LOG_LEVEL, ERROR, 1, "Session creation failed 0x%02x\n", data[1]); - private->sessions[session_number].state = S_STATE_IDLE; - pthread_mutex_unlock(&private->sessions[session_number].session_lock); - - // inform upper layers - pthread_mutex_lock(&private->setcallback_lock); - en50221_sl_session_callback cb = private->session; - void *cb_arg = private->session_arg; - pthread_mutex_unlock(&private->setcallback_lock); - if (cb) - cb(cb_arg, S_SCALLBACK_REASON_CONNECTFAIL, slot_id, session_number, - private->sessions[session_number].resource_id); - return; - } - - // set it active - private->sessions[session_number].state = S_STATE_ACTIVE; - pthread_mutex_unlock(&private->sessions[session_number].session_lock); - - // inform upper layers - pthread_mutex_lock(&private->setcallback_lock); - en50221_sl_session_callback cb = private->session; - void *cb_arg = private->session_arg; - pthread_mutex_unlock(&private->setcallback_lock); - if (cb) - cb(cb_arg, S_SCALLBACK_REASON_CONNECTED, slot_id, session_number, - private->sessions[session_number].resource_id); + // check + if (data_length < 8) { + print(LOG_LEVEL, ERROR, 1, + "Received data with invalid length from module on slot %02x\n", + slot_id); + return; + } + if (data[0] != 7) { + print(LOG_LEVEL, ERROR, 1, + "Received data with invalid length from module on slot %02x\n", + slot_id); + return; + } + // extract session number + uint16_t session_number = (data[5] << 8) | data[6]; + + // check session number is ok + if (session_number >= sl->max_sessions) { + print(LOG_LEVEL, ERROR, 1, "Received bad session id %i\n", + slot_id); + return; + } + + pthread_mutex_lock(&sl->sessions[session_number].session_lock); + if (slot_id != sl->sessions[session_number].slot_id) { + print(LOG_LEVEL, ERROR, 1, + "Received unexpected session on invalid slot %i\n", + slot_id); + pthread_mutex_unlock(&sl->sessions[session_number].session_lock); + return; + } + if (connection_id != sl->sessions[session_number].connection_id) { + print(LOG_LEVEL, ERROR, 1, + "Received unexpected session on invalid slot %i\n", + slot_id); + pthread_mutex_unlock(&sl->sessions[session_number].session_lock); + return; + } + if (sl->sessions[session_number].state != S_STATE_IN_CREATION) { + print(LOG_LEVEL, ERROR, 1, + "Received unexpected session on invalid slot %i\n", + slot_id); + pthread_mutex_unlock(&sl->sessions[session_number].session_lock); + return; + } + // extract status + if (data[1] != S_STATUS_OPEN) { + print(LOG_LEVEL, ERROR, 1, + "Session creation failed 0x%02x\n", data[1]); + sl->sessions[session_number].state = S_STATE_IDLE; + pthread_mutex_unlock(&sl->sessions[session_number].session_lock); + + // inform upper layers + pthread_mutex_lock(&sl->setcallback_lock); + en50221_sl_session_callback cb = sl->session; + void *cb_arg = sl->session_arg; + pthread_mutex_unlock(&sl->setcallback_lock); + if (cb) + cb(cb_arg, S_SCALLBACK_REASON_CONNECTFAIL, slot_id, + session_number, + sl->sessions[session_number].resource_id); + return; + } + // set it active + sl->sessions[session_number].state = S_STATE_ACTIVE; + pthread_mutex_unlock(&sl->sessions[session_number].session_lock); + + // inform upper layers + pthread_mutex_lock(&sl->setcallback_lock); + en50221_sl_session_callback cb = sl->session; + void *cb_arg = sl->session_arg; + pthread_mutex_unlock(&sl->setcallback_lock); + if (cb) + cb(cb_arg, S_SCALLBACK_REASON_CONNECTED, slot_id, + session_number, + sl->sessions[session_number].resource_id); } -static void en50221_sl_handle_close_session_response(struct en50221_session_layer_private *private, - uint8_t *data, uint32_t data_length, uint8_t slot_id, uint8_t connection_id) +static void en50221_sl_handle_close_session_response(struct en50221_session_layer *sl, + uint8_t *data, + uint32_t data_length, + uint8_t slot_id, + uint8_t connection_id) { - // check - if (data_length < 5) { - print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id); - return; - } - if (data[0] != 4) { - print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id); - return; - } - - // extract session number - uint16_t session_number = (data[2] << 8) | data[3]; - - // check session number is ok - if (session_number >= private->max_sessions) { - print(LOG_LEVEL, ERROR, 1, "Received bad session id %i\n", slot_id); - return; - } - - pthread_mutex_lock(&private->sessions[session_number].session_lock); - if (slot_id != private->sessions[session_number].slot_id) { - print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id); - pthread_mutex_unlock(&private->sessions[session_number].session_lock); - return; - } - if (connection_id != private->sessions[session_number].connection_id) { - print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id); - pthread_mutex_unlock(&private->sessions[session_number].session_lock); - return; - } - if (private->sessions[session_number].state != S_STATE_IN_DELETION) { - print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id); - pthread_mutex_unlock(&private->sessions[session_number].session_lock); - return; - } - - // extract status - if (data[1] != 0x00) { - print(LOG_LEVEL, ERROR, 1, "Session close failed 0x%02x\n", data[1]); - // just fallthrough anyway - } - - // completed - private->sessions[session_number].state = S_STATE_IDLE; - pthread_mutex_unlock(&private->sessions[session_number].session_lock); + // check + if (data_length < 5) { + print(LOG_LEVEL, ERROR, 1, + "Received data with invalid length from module on slot %02x\n", + slot_id); + return; + } + if (data[0] != 4) { + print(LOG_LEVEL, ERROR, 1, + "Received data with invalid length from module on slot %02x\n", + slot_id); + return; + } + // extract session number + uint16_t session_number = (data[2] << 8) | data[3]; + + // check session number is ok + if (session_number >= sl->max_sessions) { + print(LOG_LEVEL, ERROR, 1, "Received bad session id %i\n", slot_id); + return; + } + + pthread_mutex_lock(&sl->sessions[session_number].session_lock); + if (slot_id != sl->sessions[session_number].slot_id) { + print(LOG_LEVEL, ERROR, 1, + "Received unexpected session on invalid slot %i\n", + slot_id); + pthread_mutex_unlock(&sl->sessions[session_number].session_lock); + return; + } + if (connection_id != sl->sessions[session_number].connection_id) { + print(LOG_LEVEL, ERROR, 1, + "Received unexpected session on invalid slot %i\n", + slot_id); + pthread_mutex_unlock(&sl->sessions[session_number].session_lock); + return; + } + if (sl->sessions[session_number].state != S_STATE_IN_DELETION) { + print(LOG_LEVEL, ERROR, 1, + "Received unexpected session on invalid slot %i\n", + slot_id); + pthread_mutex_unlock(&sl->sessions[session_number].session_lock); + return; + } + // extract status + if (data[1] != 0x00) { + print(LOG_LEVEL, ERROR, 1, "Session close failed 0x%02x\n", data[1]); + // just fallthrough anyway + } + // completed + sl->sessions[session_number].state = S_STATE_IDLE; + pthread_mutex_unlock(&sl->sessions[session_number].session_lock); } -static void en50221_sl_handle_session_package(struct en50221_session_layer_private *private, - uint8_t *data, uint32_t data_length, - uint8_t slot_id, uint8_t connection_id) +static void en50221_sl_handle_session_package(struct en50221_session_layer *sl, + uint8_t *data, + uint32_t data_length, + uint8_t slot_id, + uint8_t connection_id) { - // check - if (data_length < 3) { - print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %i\n", slot_id); - return; - } - if (data[0] != 2) { - print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %i\n", slot_id); - return; - } - - // get session number - uint16_t session_number = (data[1] << 8) | data[2]; - - // check it - if (session_number >= private->max_sessions) { - print(LOG_LEVEL, ERROR, 1, "Received data with bad session_number from module on slot %i\n", slot_id); - return; - } - - pthread_mutex_lock(&private->sessions[session_number].session_lock); - if (slot_id != private->sessions[session_number].slot_id) { - print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id); - pthread_mutex_unlock(&private->sessions[session_number].session_lock); - return; - } - if (connection_id != private->sessions[session_number].connection_id) { - print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id); - pthread_mutex_unlock(&private->sessions[session_number].session_lock); - return; - } - if (private->sessions[session_number].state != S_STATE_ACTIVE) { - print(LOG_LEVEL, ERROR, 1, "Received data with bad session_number from module on slot %i\n", slot_id); - pthread_mutex_unlock(&private->sessions[session_number].session_lock); - return; - } - - en50221_sl_resource_callback cb = private->sessions[session_number].callback; - void *cb_arg = private->sessions[session_number].callback_arg; - uint32_t resource_id = private->sessions[session_number].resource_id; - pthread_mutex_unlock(&private->sessions[session_number].session_lock); - - // there can be > 1 APDU following the package - all for the same session/resource_id tho. - data += 3; - data_length -= 3; - while(data_length) { - // check length field - if (data_length < 3) { - print(LOG_LEVEL, ERROR, 1, "Received invalid sized session package from slot %i\n", slot_id); - return; - } - - // parse the APDU's length field - int length_field_len; - uint16_t asn_data_length; - if ((length_field_len = asn_1_decode(&asn_data_length, data+3, data_length-3)) < 0) { - print(LOG_LEVEL, ERROR, 1, "Received invalid sized session package from slot %i\n", slot_id); - return; - } - uint32_t apdu_length = 3 + length_field_len + asn_data_length; - - // check there is enough data - if (apdu_length > data_length) { - print(LOG_LEVEL, ERROR, 1, "Received invalid sized session package from slot %i\n", slot_id); - return; - } - - // pass the APDU up to the higher layers - if (cb) - cb(cb_arg, slot_id, session_number, resource_id, data, apdu_length); - - // next! - data += apdu_length; - data_length -= apdu_length; - } + // check + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, + "Received data with invalid length from module on slot %i\n", + slot_id); + return; + } + if (data[0] != 2) { + print(LOG_LEVEL, ERROR, 1, + "Received data with invalid length from module on slot %i\n", + slot_id); + return; + } + // get session number + uint16_t session_number = (data[1] << 8) | data[2]; + + // check it + if (session_number >= sl->max_sessions) { + print(LOG_LEVEL, ERROR, 1, + "Received data with bad session_number from module on slot %i\n", + slot_id); + return; + } + + pthread_mutex_lock(&sl->sessions[session_number].session_lock); + if (slot_id != sl->sessions[session_number].slot_id) { + print(LOG_LEVEL, ERROR, 1, + "Received unexpected session on invalid slot %i\n", + slot_id); + pthread_mutex_unlock(&sl->sessions[session_number].session_lock); + return; + } + if (connection_id != sl->sessions[session_number].connection_id) { + print(LOG_LEVEL, ERROR, 1, + "Received unexpected session on invalid slot %i\n", + slot_id); + pthread_mutex_unlock(&sl->sessions[session_number].session_lock); + return; + } + if (sl->sessions[session_number].state != S_STATE_ACTIVE) { + print(LOG_LEVEL, ERROR, 1, + "Received data with bad session_number from module on slot %i\n", + slot_id); + pthread_mutex_unlock(&sl->sessions[session_number].session_lock); + return; + } + + en50221_sl_resource_callback cb = sl->sessions[session_number].callback; + void *cb_arg = sl->sessions[session_number].callback_arg; + uint32_t resource_id = sl->sessions[session_number].resource_id; + pthread_mutex_unlock(&sl->sessions[session_number].session_lock); + + // there can be > 1 APDU following the package - all for the same session/resource_id tho. + data += 3; + data_length -= 3; + while (data_length) { + // check length field + if (data_length < 3) { + print(LOG_LEVEL, ERROR, 1, + "Received invalid sized session package from slot %i\n", + slot_id); + return; + } + // parse the APDU's length field + int length_field_len; + uint16_t asn_data_length; + if ((length_field_len = asn_1_decode(&asn_data_length, data + 3, data_length - 3)) < 0) { + print(LOG_LEVEL, ERROR, 1, + "Received invalid sized session package from slot %i\n", + slot_id); + return; + } + uint32_t apdu_length = 3 + length_field_len + asn_data_length; + + // check there is enough data + if (apdu_length > data_length) { + print(LOG_LEVEL, ERROR, 1, + "Received invalid sized session package from slot %i\n", + slot_id); + return; + } + // pass the APDU up to the higher layers + if (cb) + cb(cb_arg, slot_id, session_number, resource_id, data, apdu_length); + + // next! + data += apdu_length; + data_length -= apdu_length; + } } -static void en50221_sl_transport_callback(void *arg, int reason, uint8_t *data, uint32_t data_length, - uint8_t slot_id, uint8_t connection_id) +static void en50221_sl_transport_callback(void *arg, int reason, + uint8_t *data, + uint32_t data_length, + uint8_t slot_id, + uint8_t connection_id) { - struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) arg; - uint32_t i; - - // deal with the reason for this callback - switch(reason) { - case T_CALLBACK_REASON_DATA: - // fallthrough into rest of this function - break; - - case T_CALLBACK_REASON_CONNECTIONOPEN: - { - pthread_mutex_lock(&private->setcallback_lock); - en50221_sl_session_callback cb = private->session; - void *cb_arg = private->session_arg; - pthread_mutex_unlock(&private->setcallback_lock); - - if (cb) - cb(cb_arg, S_SCALLBACK_REASON_TC_CONNECT, slot_id, connection_id, 0); - return; - } - - case T_CALLBACK_REASON_CAMCONNECTIONOPEN: - { - pthread_mutex_lock(&private->setcallback_lock); - en50221_sl_session_callback cb = private->session; - void *cb_arg = private->session_arg; - pthread_mutex_unlock(&private->setcallback_lock); - - if (cb) - cb(cb_arg, S_SCALLBACK_REASON_TC_CAMCONNECT, slot_id, connection_id, 0); - return; - } - - case T_CALLBACK_REASON_CONNECTIONCLOSE: - { - pthread_mutex_lock(&private->setcallback_lock); - en50221_sl_session_callback cb = private->session; - void *cb_arg = private->session_arg; - pthread_mutex_unlock(&private->setcallback_lock); - - for(i=0; i< private->max_sessions; i++) { - pthread_mutex_lock(&private->sessions[i].session_lock); - - if (private->sessions[i].state == S_STATE_IDLE) { - pthread_mutex_unlock(&private->sessions[i].session_lock); - continue; - } - if (private->sessions[i].connection_id != connection_id) { - pthread_mutex_unlock(&private->sessions[i].session_lock); - continue; - } - - private->sessions[i].state = S_STATE_IDLE; - - uint8_t slot_id = private->sessions[i].slot_id; - uint32_t resource_id = private->sessions[i].resource_id; - pthread_mutex_unlock(&private->sessions[i].session_lock); - - if (cb) - cb(cb_arg, S_SCALLBACK_REASON_CLOSE, slot_id, i, resource_id); - } - return; - } - - case T_CALLBACK_REASON_SLOTCLOSE: - { - pthread_mutex_lock(&private->setcallback_lock); - en50221_sl_session_callback cb = private->session; - void *cb_arg = private->session_arg; - pthread_mutex_unlock(&private->setcallback_lock); - - for(i=0; i< private->max_sessions; i++) { - pthread_mutex_lock(&private->sessions[i].session_lock); - - if (private->sessions[i].state == S_STATE_IDLE) { - pthread_mutex_unlock(&private->sessions[i].session_lock); - continue; - } - if (private->sessions[i].slot_id != slot_id) { - pthread_mutex_unlock(&private->sessions[i].session_lock); - continue; - } - private->sessions[i].state = S_STATE_IDLE; - - uint32_t resource_id = private->sessions[i].resource_id; - pthread_mutex_unlock(&private->sessions[i].session_lock); - - if (cb) - cb(cb_arg, S_SCALLBACK_REASON_CLOSE, slot_id, i, resource_id); - - } - return; - } - } - - // sanity check data length - if (data_length < 1) { - print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %i\n", slot_id); - return; - } - - // deal with the data - uint8_t spdu_tag = data[0]; - switch(spdu_tag) - { - case ST_OPEN_SESSION_REQ: - en50221_sl_handle_open_session_request(private, data+1, data_length-1, slot_id, connection_id); - break; - - case ST_CLOSE_SESSION_REQ: - en50221_sl_handle_close_session_request(private, data+1, data_length-1, slot_id, connection_id); - break; - - case ST_SESSION_NUMBER: - en50221_sl_handle_session_package(private, data+1, data_length-1, slot_id, connection_id); - break; - - case ST_CREATE_SESSION_RES: - en50221_sl_handle_create_session_response(private, data+1, data_length-1, slot_id, connection_id); - break; - - case ST_CLOSE_SESSION_RES: - en50221_sl_handle_close_session_response(private, data+1, data_length-1, slot_id, connection_id); - break; - - default: - print(LOG_LEVEL, ERROR, 1, "Received unknown session tag %02x from module on slot %i", spdu_tag, slot_id); - break; - } + struct en50221_session_layer *sl = + (struct en50221_session_layer *) arg; + uint32_t i; + + // deal with the reason for this callback + switch (reason) { + case T_CALLBACK_REASON_DATA: + // fallthrough into rest of this function + break; + + case T_CALLBACK_REASON_CONNECTIONOPEN: + { + pthread_mutex_lock(&sl->setcallback_lock); + en50221_sl_session_callback cb = sl->session; + void *cb_arg = sl->session_arg; + pthread_mutex_unlock(&sl->setcallback_lock); + + if (cb) + cb(cb_arg, S_SCALLBACK_REASON_TC_CONNECT, + slot_id, connection_id, 0); + return; + } + + case T_CALLBACK_REASON_CAMCONNECTIONOPEN: + { + pthread_mutex_lock(&sl->setcallback_lock); + en50221_sl_session_callback cb = sl->session; + void *cb_arg = sl->session_arg; + pthread_mutex_unlock(&sl->setcallback_lock); + + if (cb) + cb(cb_arg, + S_SCALLBACK_REASON_TC_CAMCONNECT, + slot_id, connection_id, 0); + return; + } + + case T_CALLBACK_REASON_CONNECTIONCLOSE: + { + pthread_mutex_lock(&sl->setcallback_lock); + en50221_sl_session_callback cb = sl->session; + void *cb_arg = sl->session_arg; + pthread_mutex_unlock(&sl->setcallback_lock); + + for (i = 0; i < sl->max_sessions; i++) { + pthread_mutex_lock(&sl->sessions[i].session_lock); + + if (sl->sessions[i].state == S_STATE_IDLE) { + pthread_mutex_unlock(&sl->sessions[i].session_lock); + continue; + } + if (sl->sessions[i].connection_id != connection_id) { + pthread_mutex_unlock(&sl->sessions[i].session_lock); + continue; + } + + sl->sessions[i].state = S_STATE_IDLE; + + uint8_t _slot_id = sl->sessions[i].slot_id; + uint32_t resource_id = sl->sessions[i].resource_id; + pthread_mutex_unlock(&sl->sessions[i].session_lock); + + if (cb) + cb(cb_arg, S_SCALLBACK_REASON_CLOSE, _slot_id, i, resource_id); + } + return; + } + + case T_CALLBACK_REASON_SLOTCLOSE: + { + pthread_mutex_lock(&sl->setcallback_lock); + en50221_sl_session_callback cb = sl->session; + void *cb_arg = sl->session_arg; + pthread_mutex_unlock(&sl->setcallback_lock); + + for (i = 0; i < sl->max_sessions; i++) { + pthread_mutex_lock(&sl->sessions[i].session_lock); + + if (sl->sessions[i].state == S_STATE_IDLE) { + pthread_mutex_unlock(&sl->sessions[i].session_lock); + continue; + } + if (sl->sessions[i].slot_id != slot_id) { + pthread_mutex_unlock(&sl->sessions[i].session_lock); + continue; + } + sl->sessions[i].state = S_STATE_IDLE; + + uint32_t resource_id = sl->sessions[i].resource_id; + pthread_mutex_unlock(&sl->sessions[i].session_lock); + + if (cb) + cb(cb_arg, S_SCALLBACK_REASON_CLOSE, slot_id, i, resource_id); + + } + return; + } + } + + // sanity check data length + if (data_length < 1) { + print(LOG_LEVEL, ERROR, 1, + "Received data with invalid length from module on slot %i\n", + slot_id); + return; + } + // deal with the data + uint8_t spdu_tag = data[0]; + switch (spdu_tag) { + case ST_OPEN_SESSION_REQ: + en50221_sl_handle_open_session_request(sl, data + 1, + data_length - 1, + slot_id, + connection_id); + break; + + case ST_CLOSE_SESSION_REQ: + en50221_sl_handle_close_session_request(sl, data + 1, + data_length - 1, + slot_id, + connection_id); + break; + + case ST_SESSION_NUMBER: + en50221_sl_handle_session_package(sl, data + 1, + data_length - 1, slot_id, + connection_id); + break; + + case ST_CREATE_SESSION_RES: + en50221_sl_handle_create_session_response(sl, data + 1, + data_length - 1, + slot_id, + connection_id); + break; + + case ST_CLOSE_SESSION_RES: + en50221_sl_handle_close_session_response(sl, data + 1, + data_length - 1, + slot_id, + connection_id); + break; + + default: + print(LOG_LEVEL, ERROR, 1, + "Received unknown session tag %02x from module on slot %i", + spdu_tag, slot_id); + break; + } } -static int en50221_sl_alloc_new_session(struct en50221_session_layer_private *private, - uint32_t resource_id, - uint8_t slot_id, - uint8_t connection_id, - en50221_sl_resource_callback callback, void* arg) +static int en50221_sl_alloc_new_session(struct en50221_session_layer *sl, + uint32_t resource_id, + uint8_t slot_id, + uint8_t connection_id, + en50221_sl_resource_callback + callback, void *arg) { - int session_number = -1; - uint32_t i; - for(i = 1; i < private->max_sessions; i++) { - if (private->sessions[i].state == S_STATE_IDLE) { - session_number = i; - break; - } - } - if (session_number == -1) { - private->error = EN50221ERR_OUTOFSESSIONS; - return -1; - } - - // setup the session - private->sessions[session_number].state = S_STATE_IN_CREATION; - private->sessions[session_number].resource_id = resource_id; - private->sessions[session_number].slot_id = slot_id; - private->sessions[session_number].connection_id = connection_id; - private->sessions[session_number].callback = callback; - private->sessions[session_number].callback_arg = arg; - - // ok - return session_number; + int session_number = -1; + uint32_t i; + for (i = 1; i < sl->max_sessions; i++) { + if (sl->sessions[i].state == S_STATE_IDLE) { + session_number = i; + break; + } + } + if (session_number == -1) { + sl->error = EN50221ERR_OUTOFSESSIONS; + return -1; + } + // setup the session + sl->sessions[session_number].state = S_STATE_IN_CREATION; + sl->sessions[session_number].resource_id = resource_id; + sl->sessions[session_number].slot_id = slot_id; + sl->sessions[session_number].connection_id = connection_id; + sl->sessions[session_number].callback = callback; + sl->sessions[session_number].callback_arg = arg; + + // ok + return session_number; } diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_session.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_session.h index 67031d8..7b33518 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_session.h +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_session.h @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 session layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian@jusst.de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,7 +18,7 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -26,28 +26,27 @@ #define __EN50221_SESSION_H__ #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif #include <stdlib.h> #include <stdint.h> #include <libdvben50221/en50221_transport.h> -#define S_SCALLBACK_REASON_CAMCONNECTING 0x00 // CAM originated session connecting to resource (check for availability) -#define S_SCALLBACK_REASON_CAMCONNECTED 0x01 // CAM originated session connection established succesfully -#define S_SCALLBACK_REASON_CAMCONNECTFAIL 0x02 // CAM originated session connection failed -#define S_SCALLBACK_REASON_CONNECTED 0x03 // Host originated session ACKed by CAM. -#define S_SCALLBACK_REASON_CONNECTFAIL 0x04 // Host originated session NACKed by CAM. -#define S_SCALLBACK_REASON_CLOSE 0x05 // Session closed -#define S_SCALLBACK_REASON_TC_CONNECT 0x06 // A host originated transport connection has been established. -#define S_SCALLBACK_REASON_TC_CAMCONNECT 0x07 // A CAM originated transport connection has been established. +#define S_SCALLBACK_REASON_CAMCONNECTING 0x00 // CAM originated session connecting to resource (check for availability) +#define S_SCALLBACK_REASON_CAMCONNECTED 0x01 // CAM originated session connection established succesfully +#define S_SCALLBACK_REASON_CAMCONNECTFAIL 0x02 // CAM originated session connection failed +#define S_SCALLBACK_REASON_CONNECTED 0x03 // Host originated session ACKed by CAM. +#define S_SCALLBACK_REASON_CONNECTFAIL 0x04 // Host originated session NACKed by CAM. +#define S_SCALLBACK_REASON_CLOSE 0x05 // Session closed +#define S_SCALLBACK_REASON_TC_CONNECT 0x06 // A host originated transport connection has been established. +#define S_SCALLBACK_REASON_TC_CAMCONNECT 0x07 // A CAM originated transport connection has been established. /** * Opaque type representing a session layer. */ -typedef void *en50221_session_layer; +struct en50221_session_layer; /** * Type definition for resource callback function - called by session layer when data @@ -61,9 +60,12 @@ typedef void *en50221_session_layer; * @param data_length Length of data in bytes. * @return 0 on success, or -1 on failure. */ -typedef int (*en50221_sl_resource_callback)(void *arg, uint8_t slot_id, - uint16_t session_number, uint32_t resource_id, - uint8_t *data, uint32_t data_length); +typedef int (*en50221_sl_resource_callback) (void *arg, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id, + uint8_t * data, + uint32_t data_length); /** * Type definition for resource lookup callback function - used by the session layer to @@ -80,9 +82,12 @@ typedef int (*en50221_sl_resource_callback)(void *arg, uint8_t slot_id, * -2 if it exists, but had a lower version, or * -3 if it exists, but was unavailable. */ -typedef int (*en50221_sl_lookup_callback)(void *arg, uint8_t slot_id, uint32_t requested_resource_id, - en50221_sl_resource_callback *callback_out, void **arg_out, - uint32_t *resource_id_out); +typedef int (*en50221_sl_lookup_callback) (void *arg, + uint8_t slot_id, + uint32_t requested_resource_id, + en50221_sl_resource_callback * callback_out, + void **arg_out, + uint32_t *resource_id_out); /** @@ -96,8 +101,10 @@ typedef int (*en50221_sl_lookup_callback)(void *arg, uint8_t slot_id, uint32_t r * @param resource_id Resource id. * @return 0 on sucess, or -1 on error. */ -typedef int (*en50221_sl_session_callback)(void *arg, int reason, - uint8_t slot_id, uint16_t session_number, uint32_t resource_id); +typedef int (*en50221_sl_session_callback) (void *arg, int reason, + uint8_t slot_id, + uint16_t session_number, + uint32_t resource_id); /** * Construct a new instance of the session layer. @@ -106,14 +113,15 @@ typedef int (*en50221_sl_session_callback)(void *arg, int reason, * @param max_sessions Maximum number of sessions supported. * @return The en50221_session_layer instance, or NULL on error. */ -extern en50221_session_layer en50221_sl_create(en50221_transport_layer tl, uint32_t max_sessions); +extern struct en50221_session_layer *en50221_sl_create(struct en50221_transport_layer *tl, + uint32_t max_sessions); /** * Destroy an instance of the session layer. * * @param tl The en50221_session_layer instance. */ -extern void en50221_sl_destroy(en50221_session_layer sl); +extern void en50221_sl_destroy(struct en50221_session_layer *sl); /** * Gets the last error. @@ -121,7 +129,7 @@ extern void en50221_sl_destroy(en50221_session_layer sl); * @param tl The en50221_session_layer instance. * @return One of the EN50221ERR_* values. */ -extern int en50221_sl_get_error(en50221_session_layer tl); +extern int en50221_sl_get_error(struct en50221_session_layer *tl); /** * Register the callback for resource lookup. @@ -130,8 +138,9 @@ extern int en50221_sl_get_error(en50221_session_layer tl); * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_sl_register_lookup_callback(en50221_session_layer sl, - en50221_sl_lookup_callback callback, void *arg); +extern void en50221_sl_register_lookup_callback(struct en50221_session_layer *sl, + en50221_sl_lookup_callback callback, + void *arg); /** * Register the callback for informing about session from a cam. @@ -140,8 +149,9 @@ extern void en50221_sl_register_lookup_callback(en50221_session_layer sl, * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_sl_register_session_callback(en50221_session_layer sl, - en50221_sl_session_callback callback, void *arg); +extern void en50221_sl_register_session_callback(struct en50221_session_layer *sl, + en50221_sl_session_callback callback, + void *arg); /** * Create a new session to a module in a slot. @@ -153,9 +163,11 @@ extern void en50221_sl_register_session_callback(en50221_session_layer sl, * @param arg Argument to pass to the callback. * @return The new session_number, or -1 on error. */ -extern int en50221_sl_create_session(en50221_session_layer sl, int slot_id, uint8_t connection_id, - uint32_t resource_id, - en50221_sl_resource_callback callback, void* arg); +extern int en50221_sl_create_session(struct en50221_session_layer *sl, int slot_id, + uint8_t connection_id, + uint32_t resource_id, + en50221_sl_resource_callback callback, + void *arg); /** * Destroy a session. @@ -164,7 +176,8 @@ extern int en50221_sl_create_session(en50221_session_layer sl, int slot_id, uint * @param session_number The session to destroy. * @return 0 on success, or -1 on error. */ -extern int en50221_sl_destroy_session(en50221_session_layer sl, uint16_t session_number); +extern int en50221_sl_destroy_session(struct en50221_session_layer *sl, + uint16_t session_number); /** * this function is used to take a data-block, pack into @@ -176,7 +189,10 @@ extern int en50221_sl_destroy_session(en50221_session_layer sl, uint16_t session * @param data_length Length of data in bytes. * @return 0 on success, or -1 on error. */ -extern int en50221_sl_send_data(en50221_session_layer sl, uint16_t session_number, uint8_t *data, uint16_t data_length); +extern int en50221_sl_send_data(struct en50221_session_layer *sl, + uint16_t session_number, + uint8_t * data, + uint16_t data_length); /** * this function is used to take a data-block, pack into @@ -188,8 +204,10 @@ extern int en50221_sl_send_data(en50221_session_layer sl, uint16_t session_numbe * @param iov_count Number of elements in io vector. * @return 0 on success, or -1 on error. */ -extern int en50221_sl_send_datav(en50221_session_layer sl, uint16_t session_number, - struct iovec *vector, int iov_count); +extern int en50221_sl_send_datav(struct en50221_session_layer *sl, + uint16_t session_number, + struct iovec *vector, + int iov_count); /** * this is used to send a message to all sessions, linked @@ -202,11 +220,13 @@ extern int en50221_sl_send_datav(en50221_session_layer sl, uint16_t session_numb * @param data_length Length of data in bytes. * @return 0 on success, or -1 on error. */ -extern int en50221_sl_broadcast_data(en50221_session_layer sl, int slot_id, uint32_t resource_id, - uint8_t *data, uint16_t data_length); +extern int en50221_sl_broadcast_data(struct en50221_session_layer *sl, + int slot_id, + uint32_t resource_id, + uint8_t * data, + uint16_t data_length); #ifdef __cplusplus } #endif - #endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_stdcam.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_stdcam.c new file mode 100644 index 0000000..a00a844 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_stdcam.c @@ -0,0 +1,54 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <stdio.h> +#include <unistd.h> +#include <limits.h> +#include <string.h> +#include <errno.h> +#include <libdvbapi/dvbca.h> +#include "en50221_stdcam.h" + +struct en50221_stdcam *en50221_stdcam_create(int adapter, int slotnum, + struct en50221_transport_layer *tl, + struct en50221_session_layer *sl) +{ + struct en50221_stdcam *result = NULL; + + int cafd = dvbca_open(adapter, 0); + if (cafd == -1) + return NULL; + + int ca_type = dvbca_get_interface_type(cafd, slotnum); + switch(ca_type) { + case DVBCA_INTERFACE_LINK: + result = en50221_stdcam_llci_create(cafd, slotnum, tl, sl); + break; + + case DVBCA_INTERFACE_HLCI: + result = en50221_stdcam_hlci_create(cafd, slotnum); + break; + } + + if (result == NULL) + close(cafd); + return result; +} diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_stdcam.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_stdcam.h new file mode 100644 index 0000000..154ff76 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_stdcam.h @@ -0,0 +1,102 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef EN50221_STDCAM_H +#define EN50221_STDCAM_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include <libdvben50221/en50221_app_ai.h> +#include <libdvben50221/en50221_app_ca.h> +#include <libdvben50221/en50221_app_mmi.h> +#include <libdvben50221/en50221_session.h> +#include <libdvben50221/en50221_transport.h> + +enum en50221_stdcam_status { + EN50221_STDCAM_CAM_NONE, + EN50221_STDCAM_CAM_INRESET, + EN50221_STDCAM_CAM_OK, + EN50221_STDCAM_CAM_BAD, +}; + +struct en50221_stdcam { + /* one of more of the following may be NULL if a CAM does not support it */ + struct en50221_app_ai *ai_resource; + struct en50221_app_ca *ca_resource; + struct en50221_app_mmi *mmi_resource; + + /* if any of these are -1, no connection is in place to this resource yet */ + int ai_session_number; + int ca_session_number; + int mmi_session_number; + + /* poll the stdcam instance */ + enum en50221_stdcam_status (*poll)(struct en50221_stdcam *stdcam); + + /* inform the stdcam of the current DVB time */ + void (*dvbtime)(struct en50221_stdcam *stdcam, time_t dvbtime); + + /* destroy the stdcam instance */ + void (*destroy)(struct en50221_stdcam *stdcam, int closefd); +}; + +/** + * Create an instance of the STDCAM for an LLCI interface. + * + * @param cafd FD of the CA device. + * @param slotnum Slotnum on that CA device. + * @param tl Transport layer instance to use. + * @param sl Session layer instance to use. + * @return en50221_stdcam instance, or NULL on error. + */ +extern struct en50221_stdcam *en50221_stdcam_llci_create(int cafd, int slotnum, + struct en50221_transport_layer *tl, + struct en50221_session_layer *sl); + +/** + * Create an instance of the STDCAM for an HLCI interface. + * + * @param cafd FD of the CA device. + * @param slotnum Slotnum on that CA device. + * @return en50221_stdcam instance, or NULL on error. + */ +extern struct en50221_stdcam *en50221_stdcam_hlci_create(int cafd, int slotnum); + +/** + * Convenience method to create a STDCAM interface for a ca device on a particular adapter. + * + * @param adapter The DVB adapter concerned. + * @param slotnum The ca slot number on that adapter. + * @param tl Transport layer instance to use (unused for HLCI cams). + * @param sl Session layer instance to use (unused for HLCI cams). + * @return en50221_stdcam instance, or NULL on error. + */ +extern struct en50221_stdcam *en50221_stdcam_create(int adapter, int slotnum, + struct en50221_transport_layer *tl, + struct en50221_session_layer *sl); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_stdcam_hlci.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_stdcam_hlci.c new file mode 100644 index 0000000..f21637b --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_stdcam_hlci.c @@ -0,0 +1,216 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <stdio.h> +#include <unistd.h> +#include <limits.h> +#include <string.h> +#include <errno.h> +#include <libdvbapi/dvbca.h> +#include "en50221_app_utils.h" +#include "en50221_app_tags.h" +#include "en50221_stdcam.h" + + +struct en50221_stdcam_hlci { + struct en50221_stdcam stdcam; + + int cafd; + int slotnum; + int initialised; + struct en50221_app_send_functions sendfuncs; +}; + +static void en50221_stdcam_hlci_destroy(struct en50221_stdcam *stdcam, int closefd); +static enum en50221_stdcam_status en50221_stdcam_hlci_poll(struct en50221_stdcam *stdcam); +static int hlci_cam_added(struct en50221_stdcam_hlci *hlci); +static int hlci_send_data(void *arg, uint16_t session_number, + uint8_t * data, uint16_t data_length); +static int hlci_send_datav(void *arg, uint16_t session_number, + struct iovec *vector, int iov_count); + + + + +struct en50221_stdcam *en50221_stdcam_hlci_create(int cafd, int slotnum) +{ + // try and allocate space for the HLCI stdcam + struct en50221_stdcam_hlci *hlci = + malloc(sizeof(struct en50221_stdcam_hlci)); + if (hlci == NULL) { + return NULL; + } + memset(hlci, 0, sizeof(struct en50221_stdcam_hlci)); + + // create the sendfuncs + hlci->sendfuncs.arg = hlci; + hlci->sendfuncs.send_data = hlci_send_data; + hlci->sendfuncs.send_datav = hlci_send_datav; + + // create the resources (NOTE: we just use fake session numbers here) + hlci->stdcam.ai_resource = en50221_app_ai_create(&hlci->sendfuncs); + hlci->stdcam.ai_session_number = 0; + hlci->stdcam.ca_resource = en50221_app_ca_create(&hlci->sendfuncs); + hlci->stdcam.ca_session_number = 1; +// hlci->stdcam.mmi_resource = en50221_app_mmi_create(&hlci->sendfuncs); + hlci->stdcam.mmi_session_number = -1; + + // done + hlci->stdcam.destroy = en50221_stdcam_hlci_destroy; + hlci->stdcam.poll = en50221_stdcam_hlci_poll; + hlci->slotnum = slotnum; + hlci->cafd = cafd; + return &hlci->stdcam; +} + +static void en50221_stdcam_hlci_destroy(struct en50221_stdcam *stdcam, int closefd) +{ + struct en50221_stdcam_hlci *hlci = (struct en50221_stdcam_hlci *) stdcam; + + if (hlci->stdcam.ai_resource) + en50221_app_ai_destroy(hlci->stdcam.ai_resource); + if (hlci->stdcam.ca_resource) + en50221_app_ca_destroy(hlci->stdcam.ca_resource); + if (hlci->stdcam.mmi_resource) + en50221_app_mmi_destroy(hlci->stdcam.mmi_resource); + + if (closefd) + close(hlci->cafd); + + free(hlci); +} + +static enum en50221_stdcam_status en50221_stdcam_hlci_poll(struct en50221_stdcam *stdcam) +{ + struct en50221_stdcam_hlci *hlci = (struct en50221_stdcam_hlci *) stdcam; + + switch(dvbca_get_cam_state(hlci->cafd, hlci->slotnum)) { + case DVBCA_CAMSTATE_MISSING: + hlci->initialised = 0; + break; + + case DVBCA_CAMSTATE_READY: + case DVBCA_CAMSTATE_INITIALISING: + if (!hlci->initialised) + hlci_cam_added(hlci); + break; + } + + // delay to prevent busy loop + usleep(10); + + if (!hlci->initialised) { + return EN50221_STDCAM_CAM_NONE; + } + return EN50221_STDCAM_CAM_OK; +} + + + +static int hlci_cam_added(struct en50221_stdcam_hlci *hlci) +{ + uint8_t buf[256]; + int size; + + // get application information + if (en50221_app_ai_enquiry(hlci->stdcam.ai_resource, 0)) { + return -EIO; + } + if ((size = dvbca_hlci_read(hlci->cafd, TAG_APP_INFO, buf, sizeof(buf))) < 0) { + return size; + } + if (en50221_app_ai_message(hlci->stdcam.ai_resource, 0, 0, EN50221_APP_AI_RESOURCEID, buf, size)) { + return -EIO; + } + + // we forge a fake CA_INFO here so the main app works - since it will expect a CA_INFO + // this will be replaced with a proper call (below) when the driver support is there + buf[0] = TAG_CA_INFO >> 16; + buf[1] = (uint8_t) (TAG_CA_INFO >> 8); + buf[2] = (uint8_t) TAG_CA_INFO; + buf[3] = 0; + if (en50221_app_ca_message(hlci->stdcam.ca_resource, 0, 0, EN50221_APP_CA_RESOURCEID, buf, 4)) { + return -EIO; + } + + /* + // get CA information + if (en50221_app_ca_info_enq(ca_resource, 0)) { + fprintf(stderr, "Failed to send CA INFO enquiry\n"); + cafd = -1; + return -1; + } + if ((size = dvbca_hlci_read(cafd, TAG_CA_INFO, buf, sizeof(buf))) < 0) { + fprintf(stderr, "Failed to read CA INFO\n"); + cafd = -1; + return -1; + } + if (en50221_app_ca_message(ca_resource, 0, 0, EN50221_APP_CA_RESOURCEID, buf, size)) { + fprintf(stderr, "Failed to parse CA INFO\n"); + cafd = -1; + return -1; + } + */ + + // done + hlci->initialised = 1; + return 0; +} + +static int hlci_send_data(void *arg, uint16_t session_number, + uint8_t * data, uint16_t data_length) +{ + (void) session_number; + struct en50221_stdcam_hlci *hlci = arg; + + return dvbca_hlci_write(hlci->cafd, data, data_length); +} + +static int hlci_send_datav(void *arg, uint16_t session_number, + struct iovec *vector, int iov_count) +{ + (void) session_number; + struct en50221_stdcam_hlci *hlci = arg; + + // calculate the total length of the data to send + uint32_t data_size = 0; + int i; + for (i = 0; i < iov_count; i++) { + data_size += vector[i].iov_len; + } + + // allocate memory for it + uint8_t *buf = malloc(data_size); + if (buf == NULL) { + return -1; + } + // merge the iovecs + uint32_t pos = 0; + for (i = 0; i < iov_count; i++) { + memcpy(buf + pos, vector[i].iov_base, vector[i].iov_len); + pos += vector[i].iov_len; + } + + // sendit and cleanup + int status = dvbca_hlci_write(hlci->cafd, buf, data_size); + free(buf); + return status; +} diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_stdcam_llci.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_stdcam_llci.c new file mode 100644 index 0000000..ceaa027 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_stdcam_llci.c @@ -0,0 +1,437 @@ +/* + en50221 encoder An implementation for libdvb + an implementation for the en50221 transport layer + + Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <stdio.h> +#include <unistd.h> +#include <limits.h> +#include <string.h> +#include <errno.h> +#include <libdvbapi/dvbca.h> +#include <libdvbmisc/dvbmisc.h> +#include "en50221_app_rm.h" +#include "en50221_app_datetime.h" +#include "en50221_app_utils.h" +#include "en50221_app_tags.h" +#include "en50221_stdcam.h" + +#define LLCI_RESPONSE_TIMEOUT_MS 1000 +#define LLCI_POLL_DELAY_MS 100 + +/* resource IDs we support */ +static uint32_t resource_ids[] = +{ EN50221_APP_RM_RESOURCEID, + EN50221_APP_CA_RESOURCEID, + EN50221_APP_AI_RESOURCEID, + EN50221_APP_MMI_RESOURCEID, + EN50221_APP_DATETIME_RESOURCEID, +}; +#define RESOURCE_IDS_COUNT sizeof(resource_ids)/4 + +struct llci_resource { + struct en50221_app_public_resource_id resid; + uint32_t binary_resource_id; + en50221_sl_resource_callback callback; + void *arg; +}; + +struct en50221_stdcam_llci { + struct en50221_stdcam stdcam; + + int cafd; + int slotnum; + int state; + + struct llci_resource resources[RESOURCE_IDS_COUNT]; + + struct en50221_transport_layer *tl; + struct en50221_session_layer *sl; + struct en50221_app_send_functions sendfuncs; + int tl_slot_id; + + struct en50221_app_rm *rm_resource; + + struct en50221_app_datetime *datetime_resource; + int datetime_session_number; + uint8_t datetime_response_interval; + time_t datetime_next_send; + time_t datetime_dvbtime; +}; + +static enum en50221_stdcam_status en50221_stdcam_llci_poll(struct en50221_stdcam *stdcam); +static void en50221_stdcam_llci_dvbtime(struct en50221_stdcam *stdcam, time_t dvbtime); +static void en50221_stdcam_llci_destroy(struct en50221_stdcam *stdcam, int closefd); +static void llci_cam_added(struct en50221_stdcam_llci *llci); +static void llci_cam_in_reset(struct en50221_stdcam_llci *llci); +static void llci_cam_removed(struct en50221_stdcam_llci *llci); + + +static int llci_lookup_callback(void *arg, uint8_t _slot_id, uint32_t requested_resource_id, + en50221_sl_resource_callback *callback_out, void **arg_out, + uint32_t *connected_resource_id); +static int llci_session_callback(void *arg, int reason, uint8_t _slot_id, uint16_t session_number, uint32_t resource_id); +static int llci_rm_enq_callback(void *arg, uint8_t _slot_id, uint16_t session_number); +static int llci_rm_reply_callback(void *arg, uint8_t _slot_id, uint16_t session_number, uint32_t resource_id_count, uint32_t *_resource_ids); +static int llci_rm_changed_callback(void *arg, uint8_t _slot_id, uint16_t session_number); + +static int llci_datetime_enquiry_callback(void *arg, uint8_t _slot_id, uint16_t session_number, uint8_t response_interval); + + +struct en50221_stdcam *en50221_stdcam_llci_create(int cafd, int slotnum, + struct en50221_transport_layer *tl, + struct en50221_session_layer *sl) +{ + // try and allocate space for the LLCI stdcam + struct en50221_stdcam_llci *llci = + malloc(sizeof(struct en50221_stdcam_llci)); + if (llci == NULL) { + return NULL; + } + memset(llci, 0, sizeof(struct en50221_stdcam_llci)); + + // create the sendfuncs + llci->sendfuncs.arg = sl; + llci->sendfuncs.send_data = (en50221_send_data) en50221_sl_send_data; + llci->sendfuncs.send_datav = (en50221_send_datav) en50221_sl_send_datav; + + // create the resource manager resource + int resource_idx = 0; + llci->rm_resource = en50221_app_rm_create(&llci->sendfuncs); + en50221_app_decode_public_resource_id(&llci->resources[resource_idx].resid, EN50221_APP_RM_RESOURCEID); + llci->resources[resource_idx].binary_resource_id = EN50221_APP_RM_RESOURCEID; + llci->resources[resource_idx].callback = (en50221_sl_resource_callback) en50221_app_rm_message; + llci->resources[resource_idx].arg = llci->rm_resource; + en50221_app_rm_register_enq_callback(llci->rm_resource, llci_rm_enq_callback, llci); + en50221_app_rm_register_reply_callback(llci->rm_resource, llci_rm_reply_callback, llci); + en50221_app_rm_register_changed_callback(llci->rm_resource, llci_rm_changed_callback, llci); + resource_idx++; + + // create the datetime resource + llci->datetime_resource = en50221_app_datetime_create(&llci->sendfuncs); + en50221_app_decode_public_resource_id(&llci->resources[resource_idx].resid, EN50221_APP_DATETIME_RESOURCEID); + llci->resources[resource_idx].binary_resource_id = EN50221_APP_DATETIME_RESOURCEID; + llci->resources[resource_idx].callback = (en50221_sl_resource_callback) en50221_app_datetime_message; + llci->resources[resource_idx].arg = llci->datetime_resource; + en50221_app_datetime_register_enquiry_callback(llci->datetime_resource, llci_datetime_enquiry_callback, llci); + resource_idx++; + llci->datetime_session_number = -1; + llci->datetime_response_interval = 0; + llci->datetime_next_send = 0; + llci->datetime_dvbtime = 0; + + // create the application information resource + llci->stdcam.ai_resource = en50221_app_ai_create(&llci->sendfuncs); + en50221_app_decode_public_resource_id(&llci->resources[resource_idx].resid, EN50221_APP_AI_RESOURCEID); + llci->resources[resource_idx].binary_resource_id = EN50221_APP_AI_RESOURCEID; + llci->resources[resource_idx].callback = (en50221_sl_resource_callback) en50221_app_ai_message; + llci->resources[resource_idx].arg = llci->stdcam.ai_resource; + llci->stdcam.ai_session_number = -1; + resource_idx++; + + // create the CA resource + llci->stdcam.ca_resource = en50221_app_ca_create(&llci->sendfuncs); + en50221_app_decode_public_resource_id(&llci->resources[resource_idx].resid, EN50221_APP_CA_RESOURCEID); + llci->resources[resource_idx].binary_resource_id = EN50221_APP_CA_RESOURCEID; + llci->resources[resource_idx].callback = (en50221_sl_resource_callback) en50221_app_ca_message; + llci->resources[resource_idx].arg = llci->stdcam.ca_resource; + llci->stdcam.ca_session_number = -1; + resource_idx++; + + // create the MMI resource + llci->stdcam.mmi_resource = en50221_app_mmi_create(&llci->sendfuncs); + en50221_app_decode_public_resource_id(&llci->resources[resource_idx].resid, EN50221_APP_MMI_RESOURCEID); + llci->resources[resource_idx].binary_resource_id = EN50221_APP_MMI_RESOURCEID; + llci->resources[resource_idx].callback = (en50221_sl_resource_callback) en50221_app_mmi_message; + llci->resources[resource_idx].arg = llci->stdcam.mmi_resource; + llci->stdcam.mmi_session_number = -1; + resource_idx++; + + // register session layer callbacks + en50221_sl_register_lookup_callback(sl, llci_lookup_callback, llci); + en50221_sl_register_session_callback(sl, llci_session_callback, llci); + + // done + llci->stdcam.destroy = en50221_stdcam_llci_destroy; + llci->stdcam.poll = en50221_stdcam_llci_poll; + llci->stdcam.dvbtime = en50221_stdcam_llci_dvbtime; + llci->cafd = cafd; + llci->slotnum = slotnum; + llci->tl = tl; + llci->sl = sl; + llci->tl_slot_id = -1; + llci->state = EN50221_STDCAM_CAM_INRESET; + return &llci->stdcam; +} + +static void en50221_stdcam_llci_dvbtime(struct en50221_stdcam *stdcam, time_t dvbtime) +{ + struct en50221_stdcam_llci *llci = (struct en50221_stdcam_llci *) stdcam; + + llci->datetime_dvbtime = dvbtime; +} + +static void en50221_stdcam_llci_destroy(struct en50221_stdcam *stdcam, int closefd) +{ + struct en50221_stdcam_llci *llci = (struct en50221_stdcam_llci *) stdcam; + + // "remove" the cam + llci_cam_removed(llci); + + // destroy resources + if (llci->rm_resource) + en50221_app_rm_destroy(llci->rm_resource); + if (llci->datetime_resource) + en50221_app_datetime_destroy(llci->datetime_resource); + if (llci->stdcam.ai_resource) + en50221_app_ai_destroy(llci->stdcam.ai_resource); + if (llci->stdcam.ca_resource) + en50221_app_ca_destroy(llci->stdcam.ca_resource); + if (llci->stdcam.mmi_resource) + en50221_app_mmi_destroy(llci->stdcam.mmi_resource); + + if (closefd) + close(llci->cafd); + + free(llci); +} + + + + +static enum en50221_stdcam_status en50221_stdcam_llci_poll(struct en50221_stdcam *stdcam) +{ + struct en50221_stdcam_llci *llci = (struct en50221_stdcam_llci *) stdcam; + + switch(dvbca_get_cam_state(llci->cafd, llci->slotnum)) { + case DVBCA_CAMSTATE_MISSING: + if (llci->state != EN50221_STDCAM_CAM_NONE) + llci_cam_removed(llci); + break; + + case DVBCA_CAMSTATE_READY: + if (llci->state == EN50221_STDCAM_CAM_NONE) + llci_cam_added(llci); + else if (llci->state == EN50221_STDCAM_CAM_INRESET) + llci_cam_in_reset(llci); + break; + } + + // poll the stack + int error; + if ((error = en50221_tl_poll(llci->tl)) != 0) { + print(LOG_LEVEL, ERROR, 1, "Error reported by stack:%i\n", en50221_tl_get_error(llci->tl)); + } + + // send date/time response + if (llci->datetime_session_number != -1) { + time_t cur_time = time(NULL); + if (llci->datetime_response_interval && (cur_time > llci->datetime_next_send)) { + en50221_app_datetime_send(llci->datetime_resource, + llci->datetime_session_number, + llci->datetime_dvbtime, 0); + llci->datetime_next_send = cur_time + llci->datetime_response_interval; + } + } + + return llci->state; +} + +static void llci_cam_added(struct en50221_stdcam_llci *llci) +{ + // clear down any old structures + if (llci->tl_slot_id != -1) { + llci_cam_removed(llci); + } + + // reset the CAM + dvbca_reset(llci->cafd, llci->slotnum); + llci->state = EN50221_STDCAM_CAM_INRESET; +} + +static void llci_cam_in_reset(struct en50221_stdcam_llci *llci) +{ + if (dvbca_get_cam_state(llci->cafd, llci->slotnum) != DVBCA_CAMSTATE_READY) { + return; + } + + // register the slot + if ((llci->tl_slot_id = en50221_tl_register_slot(llci->tl, llci->cafd, llci->slotnum, + LLCI_RESPONSE_TIMEOUT_MS, LLCI_POLL_DELAY_MS)) < 0) { + llci->state = EN50221_STDCAM_CAM_BAD; + return; + } + + // create a new connection on the slot + if (en50221_tl_new_tc(llci->tl, llci->tl_slot_id) < 0) { + llci->state = EN50221_STDCAM_CAM_BAD; + llci->tl_slot_id = -1; + en50221_tl_destroy_slot(llci->tl, llci->tl_slot_id); + return; + } + + llci->state = EN50221_STDCAM_CAM_OK; +} + +static void llci_cam_removed(struct en50221_stdcam_llci *llci) +{ + if (llci->tl_slot_id != -1) { + en50221_tl_destroy_slot(llci->tl, llci->tl_slot_id); + llci->tl_slot_id = -1; + llci->datetime_session_number = -1; + llci->stdcam.ai_session_number = -1; + llci->stdcam.ca_session_number = -1; + llci->stdcam.mmi_session_number = -1; + } + llci->state = EN50221_STDCAM_CAM_NONE; +} + + + +static int llci_lookup_callback(void *arg, uint8_t _slot_id, uint32_t requested_resource_id, + en50221_sl_resource_callback *callback_out, void **arg_out, + uint32_t *connected_resource_id) +{ + struct en50221_app_public_resource_id resid; + struct en50221_stdcam_llci *llci = (struct en50221_stdcam_llci *) arg; + (void) _slot_id; + + // decode the resource id + if (!en50221_app_decode_public_resource_id(&resid, requested_resource_id)) { + return -1; + } + + // try and find an instance of the resource + uint32_t i; + for(i=0; i<RESOURCE_IDS_COUNT; i++) { + if ((resid.resource_class == llci->resources[i].resid.resource_class) && + (resid.resource_type == llci->resources[i].resid.resource_type)) { + + // limit sessions to certain resources + switch(requested_resource_id) { + case EN50221_APP_DATETIME_RESOURCEID: + if (llci->datetime_session_number != -1) + return -3; + break; + case EN50221_APP_AI_RESOURCEID: + if (llci->stdcam.ai_session_number != -1) + return -3; + break; + case EN50221_APP_CA_RESOURCEID: + if (llci->stdcam.ca_session_number != -1) + return -3; + break; + case EN50221_APP_MMI_RESOURCEID: + if (llci->stdcam.mmi_session_number != -1) + return -3; + break; + } + + // resource is ok. + *callback_out = llci->resources[i].callback; + *arg_out = llci->resources[i].arg; + *connected_resource_id = llci->resources[i].binary_resource_id; + return 0; + } + } + + return -1; +} + +static int llci_session_callback(void *arg, int reason, uint8_t _slot_id, uint16_t session_number, uint32_t resource_id) +{ + struct en50221_stdcam_llci *llci = (struct en50221_stdcam_llci *) arg; + (void) _slot_id; + + switch(reason) { + case S_SCALLBACK_REASON_CAMCONNECTED: + if (resource_id == EN50221_APP_RM_RESOURCEID) { + en50221_app_rm_enq(llci->rm_resource, session_number); + } else if (resource_id == EN50221_APP_DATETIME_RESOURCEID) { + llci->datetime_session_number = session_number; + } else if (resource_id == EN50221_APP_AI_RESOURCEID) { + en50221_app_ai_enquiry(llci->stdcam.ai_resource, session_number); + llci->stdcam.ai_session_number = session_number; + } else if (resource_id == EN50221_APP_CA_RESOURCEID) { + en50221_app_ca_info_enq(llci->stdcam.ca_resource, session_number); + llci->stdcam.ca_session_number = session_number; + } else if (resource_id == EN50221_APP_MMI_RESOURCEID) { + llci->stdcam.mmi_session_number = session_number; + } + + break; + case S_SCALLBACK_REASON_CLOSE: + if (resource_id == EN50221_APP_MMI_RESOURCEID) { + llci->stdcam.mmi_session_number = -1; + } + + break; + } + return 0; +} + +static int llci_rm_enq_callback(void *arg, uint8_t _slot_id, uint16_t session_number) +{ + struct en50221_stdcam_llci *llci = (struct en50221_stdcam_llci *) arg; + (void) _slot_id; + + if (en50221_app_rm_reply(llci->rm_resource, session_number, RESOURCE_IDS_COUNT, resource_ids)) { + print(LOG_LEVEL, ERROR, 1, "Failed to send RM ENQ on slot %02x\n", _slot_id); + } + return 0; +} + +static int llci_rm_reply_callback(void *arg, uint8_t _slot_id, uint16_t session_number, uint32_t resource_id_count, uint32_t *_resource_ids) +{ + struct en50221_stdcam_llci *llci = (struct en50221_stdcam_llci *) arg; + (void) _slot_id; + (void) resource_id_count; + (void) _resource_ids; + + if (en50221_app_rm_changed(llci->rm_resource, session_number)) { + print(LOG_LEVEL, ERROR, 1, "Failed to send RM REPLY on slot %02x\n", _slot_id); + } + return 0; +} + +static int llci_rm_changed_callback(void *arg, uint8_t _slot_id, uint16_t session_number) +{ + struct en50221_stdcam_llci *llci = (struct en50221_stdcam_llci *) arg; + (void) _slot_id; + + if (en50221_app_rm_enq(llci->rm_resource, session_number)) { + print(LOG_LEVEL, ERROR, 1, "Failed to send RM CHANGED on slot %02x\n", _slot_id); + } + return 0; +} + +static int llci_datetime_enquiry_callback(void *arg, uint8_t _slot_id, uint16_t session_number, uint8_t response_interval) +{ + struct en50221_stdcam_llci *llci = (struct en50221_stdcam_llci *) arg; + (void) _slot_id; + + llci->datetime_response_interval = response_interval; + llci->datetime_next_send = 0; + if (response_interval) { + llci->datetime_next_send = time(NULL) + response_interval; + } + en50221_app_datetime_send(llci->datetime_resource, session_number, llci->datetime_dvbtime, 0); + + return 0; +} diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_transport.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_transport.c index 015c127..f6f46db 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_transport.c +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_transport.c @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 transport layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,7 +18,7 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <stdio.h> @@ -37,1204 +37,1260 @@ // these are the Transport Tags, like // described in EN50221, Annex A.4.1.13 (pg70) -#define T_SB 0x80 // sb primitive h<--m -#define T_RCV 0x81 // receive primitive h-->m -#define T_CREATE_T_C 0x82 // create transport connection primitive h-->m -#define T_C_T_C_REPLY 0x83 // ctc reply primitive h<--m -#define T_DELETE_T_C 0x84 // delete tc primitive h<->m -#define T_D_T_C_REPLY 0x85 // dtc reply primitive h<->m -#define T_REQUEST_T_C 0x86 // request transport connection primitive h<--m -#define T_NEW_T_C 0x87 // new tc / reply to t_request primitive h-->m -#define T_T_C_ERROR 0x77 // error creating tc primitive h-->m -#define T_DATA_LAST 0xA0 // convey data from higher constructed h<->m - // layers -#define T_DATA_MORE 0xA1 // convey data from higher constructed h<->m - // layers +#define T_SB 0x80 // sb primitive h<--m +#define T_RCV 0x81 // receive primitive h-->m +#define T_CREATE_T_C 0x82 // create transport connection primitive h-->m +#define T_C_T_C_REPLY 0x83 // ctc reply primitive h<--m +#define T_DELETE_T_C 0x84 // delete tc primitive h<->m +#define T_D_T_C_REPLY 0x85 // dtc reply primitive h<->m +#define T_REQUEST_T_C 0x86 // request transport connection primitive h<--m +#define T_NEW_T_C 0x87 // new tc / reply to t_request primitive h-->m +#define T_T_C_ERROR 0x77 // error creating tc primitive h-->m +#define T_DATA_LAST 0xA0 // convey data from higher constructed h<->m + // layers +#define T_DATA_MORE 0xA1 // convey data from higher constructed h<->m + // layers struct en50221_message { - struct en50221_message *next; - uint32_t length; - uint8_t data[0]; + struct en50221_message *next; + uint32_t length; + uint8_t data[0]; }; struct en50221_connection { - uint32_t state; // the current state: idle/in_delete/in_create/active - struct timeval tx_time; // time last request was sent from host->module, or 0 if ok - struct timeval last_poll_time; // time of last poll transmission - uint8_t *chain_buffer; // used to save parts of chained packets - uint32_t buffer_length; - - struct en50221_message *send_queue; - struct en50221_message *send_queue_tail; + uint32_t state; // the current state: idle/in_delete/in_create/active + struct timeval tx_time; // time last request was sent from host->module, or 0 if ok + struct timeval last_poll_time; // time of last poll transmission + uint8_t *chain_buffer; // used to save parts of chained packets + uint32_t buffer_length; + + struct en50221_message *send_queue; + struct en50221_message *send_queue_tail; }; struct en50221_slot { - int ca_hndl; - uint8_t slot; // CAM slot - struct en50221_connection *connections; + int ca_hndl; + uint8_t slot; // CAM slot + struct en50221_connection *connections; - pthread_mutex_t slot_lock; + pthread_mutex_t slot_lock; - uint32_t response_timeout; - uint32_t poll_delay; + uint32_t response_timeout; + uint32_t poll_delay; }; -struct en50221_transport_layer_private -{ - uint8_t max_slots; - uint8_t max_connections_per_slot; - struct en50221_slot *slots; - struct pollfd *slot_pollfds; - int slots_changed; +struct en50221_transport_layer { + uint8_t max_slots; + uint8_t max_connections_per_slot; + struct en50221_slot *slots; + struct pollfd *slot_pollfds; + int slots_changed; - pthread_mutex_t global_lock; - pthread_mutex_t setcallback_lock; + pthread_mutex_t global_lock; + pthread_mutex_t setcallback_lock; - int error; - int error_slot; + int error; + int error_slot; - en50221_tl_callback callback; - void *callback_arg; + en50221_tl_callback callback; + void *callback_arg; }; -static int en50221_tl_process_data(struct en50221_transport_layer_private *tl, uint8_t slot_id, - uint8_t *data, uint32_t data_length); -static int en50221_tl_poll_tc(struct en50221_transport_layer_private *tl, uint8_t slot_id, uint8_t connection_id); -static int en50221_tl_alloc_new_tc(struct en50221_transport_layer_private *tl, uint8_t slot_id); -static void queue_message(struct en50221_transport_layer_private *tl, uint8_t slot_id, - uint8_t connection_id, struct en50221_message *msg); -static int en50221_tl_handle_create_tc_reply(struct en50221_transport_layer_private *private, - uint8_t slot_id, uint8_t connection_id); -static int en50221_tl_handle_delete_tc(struct en50221_transport_layer_private *private, - uint8_t slot_id, uint8_t connection_id); -static int en50221_tl_handle_delete_tc_reply(struct en50221_transport_layer_private *private, - uint8_t slot_id, uint8_t connection_id); -static int en50221_tl_handle_request_tc(struct en50221_transport_layer_private *private, - uint8_t slot_id, uint8_t connection_id); -static int en50221_tl_handle_data_more(struct en50221_transport_layer_private *private, - uint8_t slot_id, uint8_t connection_id, - uint8_t *data, uint32_t data_length); -static int en50221_tl_handle_data_last(struct en50221_transport_layer_private *private, - uint8_t slot_id, uint8_t connection_id, - uint8_t *data, uint32_t data_length); -static int en50221_tl_handle_sb(struct en50221_transport_layer_private *private, - uint8_t slot_id, uint8_t connection_id, - uint8_t *data, uint32_t data_length); - - -en50221_transport_layer en50221_tl_create(uint8_t max_slots, uint8_t max_connections_per_slot) +static int en50221_tl_process_data(struct en50221_transport_layer *tl, + uint8_t slot_id, uint8_t * data, + uint32_t data_length); +static int en50221_tl_poll_tc(struct en50221_transport_layer *tl, + uint8_t slot_id, uint8_t connection_id); +static int en50221_tl_alloc_new_tc(struct en50221_transport_layer *tl, + uint8_t slot_id); +static void queue_message(struct en50221_transport_layer *tl, + uint8_t slot_id, uint8_t connection_id, + struct en50221_message *msg); +static int en50221_tl_handle_create_tc_reply(struct en50221_transport_layer + *tl, uint8_t slot_id, + uint8_t connection_id); +static int en50221_tl_handle_delete_tc(struct en50221_transport_layer *tl, + uint8_t slot_id, + uint8_t connection_id); +static int en50221_tl_handle_delete_tc_reply(struct en50221_transport_layer + *tl, uint8_t slot_id, + uint8_t connection_id); +static int en50221_tl_handle_request_tc(struct en50221_transport_layer *tl, + uint8_t slot_id, + uint8_t connection_id); +static int en50221_tl_handle_data_more(struct en50221_transport_layer *tl, + uint8_t slot_id, + uint8_t connection_id, + uint8_t * data, + uint32_t data_length); +static int en50221_tl_handle_data_last(struct en50221_transport_layer *tl, + uint8_t slot_id, + uint8_t connection_id, + uint8_t * data, + uint32_t data_length); +static int en50221_tl_handle_sb(struct en50221_transport_layer *tl, + uint8_t slot_id, uint8_t connection_id, + uint8_t * data, uint32_t data_length); + + +struct en50221_transport_layer *en50221_tl_create(uint8_t max_slots, + uint8_t + max_connections_per_slot) { - struct en50221_transport_layer_private *private = NULL; - int i; - int j; - - // setup structure - private = (struct en50221_transport_layer_private*) malloc(sizeof(struct en50221_transport_layer_private)); - if (private == NULL) - goto error_exit; - private->max_slots = max_slots; - private->max_connections_per_slot = max_connections_per_slot; - private->slots = NULL; - private->slot_pollfds = NULL; - private->slots_changed = 1; - private->callback = NULL; - private->callback_arg = NULL; - private->error_slot = 0; - private->error = 0; - pthread_mutex_init(&private->global_lock, NULL); - pthread_mutex_init(&private->setcallback_lock, NULL); - - // create the slots - private->slots = malloc(sizeof(struct en50221_slot) * max_slots); - if (private->slots == NULL) - goto error_exit; - - // set them up - for(i=0; i< max_slots; i++) { - private->slots[i].ca_hndl = -1; - - // create the connections for this slot - private->slots[i].connections = malloc(sizeof(struct en50221_connection) * max_connections_per_slot); - if (private->slots[i].connections == NULL) - goto error_exit; - - // create a mutex for the slot - pthread_mutex_init(&private->slots[i].slot_lock, NULL); - - // set them up - for(j = 0; j < max_connections_per_slot; j++) { - private->slots[i].connections[j].state = T_STATE_IDLE; - private->slots[i].connections[j].tx_time.tv_sec = 0; - private->slots[i].connections[j].last_poll_time.tv_sec = 0; - private->slots[i].connections[j].last_poll_time.tv_usec = 0; - private->slots[i].connections[j].chain_buffer = NULL; - private->slots[i].connections[j].buffer_length = 0; - private->slots[i].connections[j].send_queue = NULL; - private->slots[i].connections[j].send_queue_tail = NULL; - } - } - - // create the pollfds - private->slot_pollfds = malloc(sizeof(struct pollfd) * max_slots); - if (private->slot_pollfds == NULL) { - goto error_exit; - } - memset(private->slot_pollfds, 0, sizeof(struct pollfd) * max_slots); - - return private; - -error_exit: - en50221_tl_destroy(private); - return NULL; + struct en50221_transport_layer *tl = NULL; + int i; + int j; + + // setup structure + tl = (struct en50221_transport_layer *) + malloc(sizeof(struct en50221_transport_layer)); + if (tl == NULL) + goto error_exit; + tl->max_slots = max_slots; + tl->max_connections_per_slot = max_connections_per_slot; + tl->slots = NULL; + tl->slot_pollfds = NULL; + tl->slots_changed = 1; + tl->callback = NULL; + tl->callback_arg = NULL; + tl->error_slot = 0; + tl->error = 0; + pthread_mutex_init(&tl->global_lock, NULL); + pthread_mutex_init(&tl->setcallback_lock, NULL); + + // create the slots + tl->slots = malloc(sizeof(struct en50221_slot) * max_slots); + if (tl->slots == NULL) + goto error_exit; + + // set them up + for (i = 0; i < max_slots; i++) { + tl->slots[i].ca_hndl = -1; + + // create the connections for this slot + tl->slots[i].connections = + malloc(sizeof(struct en50221_connection) * max_connections_per_slot); + if (tl->slots[i].connections == NULL) + goto error_exit; + + // create a mutex for the slot + pthread_mutex_init(&tl->slots[i].slot_lock, NULL); + + // set them up + for (j = 0; j < max_connections_per_slot; j++) { + tl->slots[i].connections[j].state = T_STATE_IDLE; + tl->slots[i].connections[j].tx_time.tv_sec = 0; + tl->slots[i].connections[j].last_poll_time.tv_sec = 0; + tl->slots[i].connections[j].last_poll_time.tv_usec = 0; + tl->slots[i].connections[j].chain_buffer = NULL; + tl->slots[i].connections[j].buffer_length = 0; + tl->slots[i].connections[j].send_queue = NULL; + tl->slots[i].connections[j].send_queue_tail = NULL; + } + } + + // create the pollfds + tl->slot_pollfds = malloc(sizeof(struct pollfd) * max_slots); + if (tl->slot_pollfds == NULL) { + goto error_exit; + } + memset(tl->slot_pollfds, 0, sizeof(struct pollfd) * max_slots); + + return tl; + + error_exit: + en50221_tl_destroy(tl); + return NULL; } // Destroy an instance of the transport layer -void en50221_tl_destroy(en50221_transport_layer tl) +void en50221_tl_destroy(struct en50221_transport_layer *tl) { - struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl; - int i, j; - - if (private) { - if (private->slots) { - for(i=0; i< private->max_slots; i++) { - if (private->slots[i].connections) { - for(j=0; j<private->max_connections_per_slot; j++) { - if (private->slots[i].connections[j].chain_buffer) { - free(private->slots[i].connections[j].chain_buffer); - } - - struct en50221_message *cur_msg = private->slots[i].connections[j].send_queue; - while(cur_msg) { - struct en50221_message *next_msg = cur_msg->next; - free(cur_msg); - cur_msg = next_msg; - } - private->slots[i].connections[j].send_queue = NULL; - private->slots[i].connections[j].send_queue_tail = NULL; - } - free(private->slots[i].connections); - pthread_mutex_destroy(&private->slots[i].slot_lock); - } - } - free(private->slots); - } - if (private->slot_pollfds) { - free(private->slot_pollfds); - } - pthread_mutex_destroy(&private->setcallback_lock); - pthread_mutex_destroy(&private->global_lock); - free(private); - } + int i, j; + + if (tl) { + if (tl->slots) { + for (i = 0; i < tl->max_slots; i++) { + if (tl->slots[i].connections) { + for (j = 0; j < tl->max_connections_per_slot; j++) { + if (tl->slots[i].connections[j].chain_buffer) { + free(tl->slots[i].connections[j].chain_buffer); + } + + struct en50221_message *cur_msg = + tl->slots[i].connections[j].send_queue; + while (cur_msg) { + struct en50221_message *next_msg = cur_msg->next; + free(cur_msg); + cur_msg = next_msg; + } + tl->slots[i].connections[j].send_queue = NULL; + tl->slots[i].connections[j].send_queue_tail = NULL; + } + free(tl->slots[i].connections); + pthread_mutex_destroy(&tl->slots[i].slot_lock); + } + } + free(tl->slots); + } + if (tl->slot_pollfds) { + free(tl->slot_pollfds); + } + pthread_mutex_destroy(&tl->setcallback_lock); + pthread_mutex_destroy(&tl->global_lock); + free(tl); + } } // this can be called from the user-space app to // register new slots that we should work with -int en50221_tl_register_slot(en50221_transport_layer tl, int ca_hndl, uint8_t slot, - uint32_t response_timeout, uint32_t poll_delay) +int en50221_tl_register_slot(struct en50221_transport_layer *tl, + int ca_hndl, uint8_t slot, + uint32_t response_timeout, + uint32_t poll_delay) { - struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl; - - // lock - pthread_mutex_lock(&private->global_lock); - - // we browse through the array of slots - // to look for the first unused one - int i; - int16_t slot_id = -1; - for(i=0; i < private->max_slots; i++) { - if (private->slots[i].ca_hndl == -1) { - slot_id = i; - break; - } - } - if (slot_id == -1) { - private->error = EN50221ERR_OUTOFSLOTS; - pthread_mutex_unlock(&private->global_lock); - return -1; - } - - // set up the slot struct - pthread_mutex_lock(&private->slots[slot_id].slot_lock); - private->slots[slot_id].ca_hndl = ca_hndl; - private->slots[slot_id].slot = slot; - private->slots[slot_id].response_timeout = response_timeout; - private->slots[slot_id].poll_delay = poll_delay; - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - - private->slots_changed = 1; - pthread_mutex_unlock(&private->global_lock); - return slot_id; + // lock + pthread_mutex_lock(&tl->global_lock); + + // we browse through the array of slots + // to look for the first unused one + int i; + int16_t slot_id = -1; + for (i = 0; i < tl->max_slots; i++) { + if (tl->slots[i].ca_hndl == -1) { + slot_id = i; + break; + } + } + if (slot_id == -1) { + tl->error = EN50221ERR_OUTOFSLOTS; + pthread_mutex_unlock(&tl->global_lock); + return -1; + } + // set up the slot struct + pthread_mutex_lock(&tl->slots[slot_id].slot_lock); + tl->slots[slot_id].ca_hndl = ca_hndl; + tl->slots[slot_id].slot = slot; + tl->slots[slot_id].response_timeout = response_timeout; + tl->slots[slot_id].poll_delay = poll_delay; + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + + tl->slots_changed = 1; + pthread_mutex_unlock(&tl->global_lock); + return slot_id; } -void en50221_tl_destroy_slot(en50221_transport_layer tl, uint8_t slot_id) +void en50221_tl_destroy_slot(struct en50221_transport_layer *tl, + uint8_t slot_id) { - struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl; - int i; - - if (slot_id >= private->max_slots) - return; - - // lock - pthread_mutex_lock(&private->global_lock); - - // clear the slot - pthread_mutex_lock(&private->slots[slot_id].slot_lock); - private->slots[slot_id].ca_hndl = -1; - for(i=0; i<private->max_connections_per_slot; i++) { - private->slots[slot_id].connections[i].state = T_STATE_IDLE; - private->slots[slot_id].connections[i].tx_time.tv_sec = 0; - private->slots[slot_id].connections[i].last_poll_time.tv_sec = 0; - private->slots[slot_id].connections[i].last_poll_time.tv_usec = 0; - if (private->slots[slot_id].connections[i].chain_buffer) { - free(private->slots[slot_id].connections[i].chain_buffer); - } - private->slots[slot_id].connections[i].chain_buffer = NULL; - private->slots[slot_id].connections[i].buffer_length = 0; - - struct en50221_message *cur_msg = private->slots[slot_id].connections[i].send_queue; - while(cur_msg) { - struct en50221_message *next_msg = cur_msg->next; - free(cur_msg); - cur_msg = next_msg; - } - private->slots[slot_id].connections[i].send_queue = NULL; - private->slots[slot_id].connections[i].send_queue_tail = NULL; - } - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - - // tell upper layers - pthread_mutex_lock(&private->setcallback_lock); - en50221_tl_callback cb = private->callback; - void *cb_arg = private->callback_arg; - pthread_mutex_unlock(&private->setcallback_lock); - if (cb) - cb(cb_arg, T_CALLBACK_REASON_SLOTCLOSE, NULL, 0, slot_id, 0); - - private->slots_changed = 1; - pthread_mutex_unlock(&private->global_lock); + int i; + + if (slot_id >= tl->max_slots) + return; + + // lock + pthread_mutex_lock(&tl->global_lock); + + // clear the slot + pthread_mutex_lock(&tl->slots[slot_id].slot_lock); + tl->slots[slot_id].ca_hndl = -1; + for (i = 0; i < tl->max_connections_per_slot; i++) { + tl->slots[slot_id].connections[i].state = T_STATE_IDLE; + tl->slots[slot_id].connections[i].tx_time.tv_sec = 0; + tl->slots[slot_id].connections[i].last_poll_time.tv_sec = 0; + tl->slots[slot_id].connections[i].last_poll_time.tv_usec = 0; + if (tl->slots[slot_id].connections[i].chain_buffer) { + free(tl->slots[slot_id].connections[i]. + chain_buffer); + } + tl->slots[slot_id].connections[i].chain_buffer = NULL; + tl->slots[slot_id].connections[i].buffer_length = 0; + + struct en50221_message *cur_msg = + tl->slots[slot_id].connections[i].send_queue; + while (cur_msg) { + struct en50221_message *next_msg = cur_msg->next; + free(cur_msg); + cur_msg = next_msg; + } + tl->slots[slot_id].connections[i].send_queue = NULL; + tl->slots[slot_id].connections[i].send_queue_tail = NULL; + } + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + + // tell upper layers + pthread_mutex_lock(&tl->setcallback_lock); + en50221_tl_callback cb = tl->callback; + void *cb_arg = tl->callback_arg; + pthread_mutex_unlock(&tl->setcallback_lock); + if (cb) + cb(cb_arg, T_CALLBACK_REASON_SLOTCLOSE, NULL, 0, slot_id, 0); + + tl->slots_changed = 1; + pthread_mutex_unlock(&tl->global_lock); } -int en50221_tl_poll(en50221_transport_layer tl) +int en50221_tl_poll(struct en50221_transport_layer *tl) { - struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl; - uint8_t data[4096]; - int slot_id; - int j; - - // make up pollfds if the slots have changed - pthread_mutex_lock(&private->global_lock); - if (private->slots_changed) { - for(slot_id = 0; slot_id < private->max_slots; slot_id++) { - if (private->slots[slot_id].ca_hndl != -1) { - private->slot_pollfds[slot_id].fd = private->slots[slot_id].ca_hndl; - private->slot_pollfds[slot_id].events = POLLIN|POLLPRI|POLLERR; - private->slot_pollfds[slot_id].revents = 0; - } else { - private->slot_pollfds[slot_id].fd = 0; - private->slot_pollfds[slot_id].events = 0; - private->slot_pollfds[slot_id].revents = 0; - } - } - private->slots_changed = 0; - } - pthread_mutex_unlock(&private->global_lock); - - // anything happened? - if (poll(private->slot_pollfds, private->max_slots, 10) < 0) { - private->error_slot = -1; - private->error = EN50221ERR_CAREAD; - return -1; - } - - // go through all slots (even though poll may not have reported any events - for(slot_id = 0; slot_id < private->max_slots; slot_id++) { - - // check if this slot is still used and get its handle - pthread_mutex_lock(&private->slots[slot_id].slot_lock); - if (private->slots[slot_id].ca_hndl == -1) { - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - continue; - } - int ca_hndl = private->slots[slot_id].ca_hndl; - - if (private->slot_pollfds[slot_id].revents & (POLLPRI | POLLIN)) { - // read data - uint8_t r_slot_id; - uint8_t connection_id; - int readcnt = dvbca_link_read(ca_hndl, &r_slot_id, &connection_id, data, sizeof(data)); - if (readcnt < 0) { - private->error_slot = slot_id; - private->error = EN50221ERR_CAREAD; - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return -1; - } - - // process it if we got some - if (readcnt > 0) { - if (private->slots[slot_id].slot != r_slot_id) { - // this message is for an other CAM of the same CA - int new_slot_id; - for(new_slot_id = 0; new_slot_id < private->max_slots; new_slot_id++) { - if ((private->slots[new_slot_id].ca_hndl == ca_hndl) && (private->slots[new_slot_id].slot == r_slot_id)) - break; - } - if (new_slot_id != private->max_slots) { - // we found the requested CAM - pthread_mutex_lock(&private->slots[new_slot_id].slot_lock); - if (en50221_tl_process_data(private, new_slot_id, data, readcnt)) { - pthread_mutex_unlock(&private->slots[new_slot_id].slot_lock); - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return -1; - } - pthread_mutex_unlock(&private->slots[new_slot_id].slot_lock); - } else { - private->error = EN50221ERR_BADSLOTID; - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return -1; - } - } - else if (en50221_tl_process_data(private, slot_id, data, readcnt)) { - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return -1; - } - } - } else if (private->slot_pollfds[slot_id].revents & POLLERR) { - // an error was reported - private->error_slot = slot_id; - private->error = EN50221ERR_CAREAD; - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return -1; - } - - // poll the connections on this slot + check for timeouts - for(j=0; j < private->max_connections_per_slot; j++) { - // ignore connection if idle - if (private->slots[slot_id].connections[j].state == T_STATE_IDLE) { - continue; - } - - // send queued data - if (private->slots[slot_id].connections[j].state & (T_STATE_IN_CREATION|T_STATE_ACTIVE|T_STATE_ACTIVE_DELETEQUEUED)) { - // send data if there is some to go and we're not waiting for a response already - if (private->slots[slot_id].connections[j].send_queue && - (private->slots[slot_id].connections[j].tx_time.tv_sec == 0)) { - - // get the message - struct en50221_message *msg = private->slots[slot_id].connections[j].send_queue; - if (msg->next != NULL) { - private->slots[slot_id].connections[j].send_queue = msg->next; - } else { - private->slots[slot_id].connections[j].send_queue = NULL; - private->slots[slot_id].connections[j].send_queue_tail = NULL; - } - - // send the message - if (dvbca_link_write(private->slots[slot_id].ca_hndl, private->slots[slot_id].slot, j, msg->data, msg->length) < 0) { - free(msg); - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - private->error_slot = slot_id; - private->error = EN50221ERR_CAWRITE; - print(LOG_LEVEL, ERROR, 1, "CAWrite failed"); - return -1; - } - gettimeofday(&private->slots[slot_id].connections[j].tx_time, 0); - - // fixup connection state for T_DELETE_T_C - if (msg->length && (msg->data[0] == T_DELETE_T_C)) { - private->slots[slot_id].connections[j].state = T_STATE_IN_DELETION; - if (private->slots[slot_id].connections[j].chain_buffer) { - free(private->slots[slot_id].connections[j].chain_buffer); - } - private->slots[slot_id].connections[j].chain_buffer = NULL; - private->slots[slot_id].connections[j].buffer_length = 0; - } - - free(msg); - } - } - - // poll it if we're not expecting a reponse and the poll time has elapsed - if (private->slots[slot_id].connections[j].state & T_STATE_ACTIVE) { - if ((private->slots[slot_id].connections[j].tx_time.tv_sec == 0) && - (time_after(private->slots[slot_id].connections[j].last_poll_time, private->slots[slot_id].poll_delay))) { - - gettimeofday(&private->slots[slot_id].connections[j].last_poll_time, 0); - if (en50221_tl_poll_tc(private, slot_id, j)) { - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return -1; - } - } - } - - // check for timeouts - in any state - if (private->slots[slot_id].connections[j].tx_time.tv_sec && - (time_after(private->slots[slot_id].connections[j].tx_time, private->slots[slot_id].response_timeout))) { - - if (private->slots[slot_id].connections[j].state & (T_STATE_IN_CREATION|T_STATE_IN_DELETION)) { - private->slots[slot_id].connections[j].state = T_STATE_IDLE; - } else if (private->slots[slot_id].connections[j].state & (T_STATE_ACTIVE|T_STATE_ACTIVE_DELETEQUEUED)) { - private->error_slot = slot_id; - private->error = EN50221ERR_TIMEOUT; - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return -1; - } - } - } - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - } - - return 0; + uint8_t data[4096]; + int slot_id; + int j; + + // make up pollfds if the slots have changed + pthread_mutex_lock(&tl->global_lock); + if (tl->slots_changed) { + for (slot_id = 0; slot_id < tl->max_slots; slot_id++) { + if (tl->slots[slot_id].ca_hndl != -1) { + tl->slot_pollfds[slot_id].fd = tl->slots[slot_id].ca_hndl; + tl->slot_pollfds[slot_id].events = POLLIN | POLLPRI | POLLERR; + tl->slot_pollfds[slot_id].revents = 0; + } else { + tl->slot_pollfds[slot_id].fd = 0; + tl->slot_pollfds[slot_id].events = 0; + tl->slot_pollfds[slot_id].revents = 0; + } + } + tl->slots_changed = 0; + } + pthread_mutex_unlock(&tl->global_lock); + + // anything happened? + if (poll(tl->slot_pollfds, tl->max_slots, 10) < 0) { + tl->error_slot = -1; + tl->error = EN50221ERR_CAREAD; + return -1; + } + // go through all slots (even though poll may not have reported any events + for (slot_id = 0; slot_id < tl->max_slots; slot_id++) { + + // check if this slot is still used and get its handle + pthread_mutex_lock(&tl->slots[slot_id].slot_lock); + if (tl->slots[slot_id].ca_hndl == -1) { + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + continue; + } + int ca_hndl = tl->slots[slot_id].ca_hndl; + + if (tl->slot_pollfds[slot_id].revents & (POLLPRI | POLLIN)) { + // read data + uint8_t r_slot_id; + uint8_t connection_id; + int readcnt = dvbca_link_read(ca_hndl, &r_slot_id, + &connection_id, + data, sizeof(data)); + if (readcnt < 0) { + tl->error_slot = slot_id; + tl->error = EN50221ERR_CAREAD; + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return -1; + } + // process it if we got some + if (readcnt > 0) { + if (tl->slots[slot_id].slot != r_slot_id) { + // this message is for an other CAM of the same CA + int new_slot_id; + for (new_slot_id = 0; new_slot_id < tl->max_slots; new_slot_id++) { + if ((tl->slots[new_slot_id].ca_hndl == ca_hndl) && + (tl->slots[new_slot_id].slot == r_slot_id)) + break; + } + if (new_slot_id != tl->max_slots) { + // we found the requested CAM + pthread_mutex_lock(&tl->slots[new_slot_id].slot_lock); + if (en50221_tl_process_data(tl, new_slot_id, data, readcnt)) { + pthread_mutex_unlock(&tl->slots[new_slot_id].slot_lock); + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return -1; + } + pthread_mutex_unlock(&tl->slots[new_slot_id].slot_lock); + } else { + tl->error = EN50221ERR_BADSLOTID; + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return -1; + } + } else + if (en50221_tl_process_data(tl, slot_id, data, readcnt)) { + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return -1; + } + } + } else if (tl->slot_pollfds[slot_id].revents & POLLERR) { + // an error was reported + tl->error_slot = slot_id; + tl->error = EN50221ERR_CAREAD; + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return -1; + } + // poll the connections on this slot + check for timeouts + for (j = 0; j < tl->max_connections_per_slot; j++) { + // ignore connection if idle + if (tl->slots[slot_id].connections[j].state == T_STATE_IDLE) { + continue; + } + // send queued data + if (tl->slots[slot_id].connections[j].state & + (T_STATE_IN_CREATION | T_STATE_ACTIVE | T_STATE_ACTIVE_DELETEQUEUED)) { + // send data if there is some to go and we're not waiting for a response already + if (tl->slots[slot_id].connections[j].send_queue && + (tl->slots[slot_id].connections[j].tx_time.tv_sec == 0)) { + + // get the message + struct en50221_message *msg = + tl->slots[slot_id].connections[j].send_queue; + if (msg->next != NULL) { + tl->slots[slot_id].connections[j].send_queue = msg->next; + } else { + tl->slots[slot_id].connections[j].send_queue = NULL; + tl->slots[slot_id].connections[j].send_queue_tail = NULL; + } + + // send the message + if (dvbca_link_write(tl->slots[slot_id].ca_hndl, + tl->slots[slot_id].slot, + j, + msg->data, msg->length) < 0) { + free(msg); + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + tl->error_slot = slot_id; + tl->error = EN50221ERR_CAWRITE; + print(LOG_LEVEL, ERROR, 1, "CAWrite failed"); + return -1; + } + gettimeofday(&tl->slots[slot_id].connections[j].tx_time, 0); + + // fixup connection state for T_DELETE_T_C + if (msg->length && (msg->data[0] == T_DELETE_T_C)) { + tl->slots[slot_id].connections[j].state = T_STATE_IN_DELETION; + if (tl->slots[slot_id].connections[j].chain_buffer) { + free(tl->slots[slot_id].connections[j].chain_buffer); + } + tl->slots[slot_id].connections[j].chain_buffer = NULL; + tl->slots[slot_id].connections[j].buffer_length = 0; + } + + free(msg); + } + } + // poll it if we're not expecting a reponse and the poll time has elapsed + if (tl->slots[slot_id].connections[j].state & T_STATE_ACTIVE) { + if ((tl->slots[slot_id].connections[j].tx_time.tv_sec == 0) && + (time_after(tl->slots[slot_id].connections[j].last_poll_time, + tl->slots[slot_id].poll_delay))) { + + gettimeofday(&tl->slots[slot_id].connections[j].last_poll_time, 0); + if (en50221_tl_poll_tc(tl, slot_id, j)) { + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return -1; + } + } + } + + // check for timeouts - in any state + if (tl->slots[slot_id].connections[j].tx_time.tv_sec && + (time_after(tl->slots[slot_id].connections[j].tx_time, + tl->slots[slot_id].response_timeout))) { + + if (tl->slots[slot_id].connections[j].state & + (T_STATE_IN_CREATION |T_STATE_IN_DELETION)) { + tl->slots[slot_id].connections[j].state = T_STATE_IDLE; + } else if (tl->slots[slot_id].connections[j].state & + (T_STATE_ACTIVE | T_STATE_ACTIVE_DELETEQUEUED)) { + tl->error_slot = slot_id; + tl->error = EN50221ERR_TIMEOUT; + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return -1; + } + } + } + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + } + + return 0; } -void en50221_tl_register_callback(en50221_transport_layer tl, en50221_tl_callback callback, void *arg) +void en50221_tl_register_callback(struct en50221_transport_layer *tl, + en50221_tl_callback callback, void *arg) { - struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl; - - pthread_mutex_lock(&private->setcallback_lock); - private->callback = callback; - private->callback_arg = arg; - pthread_mutex_unlock(&private->setcallback_lock); + pthread_mutex_lock(&tl->setcallback_lock); + tl->callback = callback; + tl->callback_arg = arg; + pthread_mutex_unlock(&tl->setcallback_lock); } -int en50221_tl_get_error_slot(en50221_transport_layer tl) +int en50221_tl_get_error_slot(struct en50221_transport_layer *tl) { - struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl; - return private->error_slot; + return tl->error_slot; } -int en50221_tl_get_error(en50221_transport_layer tl) +int en50221_tl_get_error(struct en50221_transport_layer *tl) { - struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl; - return private->error; + return tl->error; } -int en50221_tl_send_data(en50221_transport_layer tl, uint8_t slot_id, uint8_t connection_id, - uint8_t *data, uint32_t data_size) +int en50221_tl_send_data(struct en50221_transport_layer *tl, + uint8_t slot_id, uint8_t connection_id, + uint8_t * data, uint32_t data_size) { - struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl; - #ifdef DEBUG_TXDATA - printf("[[[[[[[[[[[[[[[[[[[[\n"); - uint32_t ii=0; - for(ii=0;ii<data_size;ii++) { - printf("%02x: %02x\n", ii, data[ii]); - } - printf("]]]]]]]]]]]]]]]]]]]]\n"); + printf("[[[[[[[[[[[[[[[[[[[[\n"); + uint32_t ii = 0; + for (ii = 0; ii < data_size; ii++) { + printf("%02x: %02x\n", ii, data[ii]); + } + printf("]]]]]]]]]]]]]]]]]]]]\n"); #endif - if (slot_id >= private->max_slots) { - private->error = EN50221ERR_BADSLOTID; - return -1; - } - - pthread_mutex_lock(&private->slots[slot_id].slot_lock); - if (private->slots[slot_id].ca_hndl == -1) { - private->error = EN50221ERR_BADSLOTID; - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return -1; - } - if (connection_id >= private->max_connections_per_slot) { - private->error_slot = slot_id; - private->error = EN50221ERR_BADCONNECTIONID; - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return -1; - } - if (private->slots[slot_id].connections[connection_id].state != T_STATE_ACTIVE) { - private->error = EN50221ERR_BADCONNECTIONID; - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return -1; - } - - // allocate msg structure - struct en50221_message *msg = malloc(sizeof(struct en50221_message)+data_size+10); - if (msg == NULL) { - private->error_slot = slot_id; - private->error = EN50221ERR_OUTOFMEMORY; - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return -1; - } - - // make up data to send - int length_field_len; - msg->data[0] = T_DATA_LAST; - if ((length_field_len = asn_1_encode(data_size + 1, msg->data + 1, 3)) < 0) { - free(msg); - private->error_slot = slot_id; - private->error = EN50221ERR_ASNENCODE; - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return -1; - } - msg->data[1 + length_field_len] = connection_id; - memcpy(msg->data+1+length_field_len+1, data, data_size); - msg->length = 1+length_field_len+1+data_size; - - // queue it for transmission - queue_message(private, slot_id, connection_id, msg); - - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return 0; + if (slot_id >= tl->max_slots) { + tl->error = EN50221ERR_BADSLOTID; + return -1; + } + + pthread_mutex_lock(&tl->slots[slot_id].slot_lock); + if (tl->slots[slot_id].ca_hndl == -1) { + tl->error = EN50221ERR_BADSLOTID; + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return -1; + } + if (connection_id >= tl->max_connections_per_slot) { + tl->error_slot = slot_id; + tl->error = EN50221ERR_BADCONNECTIONID; + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return -1; + } + if (tl->slots[slot_id].connections[connection_id].state != T_STATE_ACTIVE) { + tl->error = EN50221ERR_BADCONNECTIONID; + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return -1; + } + // allocate msg structure + struct en50221_message *msg = + malloc(sizeof(struct en50221_message) + data_size + 10); + if (msg == NULL) { + tl->error_slot = slot_id; + tl->error = EN50221ERR_OUTOFMEMORY; + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return -1; + } + // make up data to send + int length_field_len; + msg->data[0] = T_DATA_LAST; + if ((length_field_len = asn_1_encode(data_size + 1, msg->data + 1, 3)) < 0) { + free(msg); + tl->error_slot = slot_id; + tl->error = EN50221ERR_ASNENCODE; + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return -1; + } + msg->data[1 + length_field_len] = connection_id; + memcpy(msg->data + 1 + length_field_len + 1, data, data_size); + msg->length = 1 + length_field_len + 1 + data_size; + + // queue it for transmission + queue_message(tl, slot_id, connection_id, msg); + + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return 0; } -int en50221_tl_send_datav(en50221_transport_layer tl, uint8_t slot_id, uint8_t connection_id, - struct iovec *vector, int iov_count) +int en50221_tl_send_datav(struct en50221_transport_layer *tl, + uint8_t slot_id, uint8_t connection_id, + struct iovec *vector, int iov_count) { - struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl; - #ifdef DEBUG_TXDATA - printf("[[[[[[[[[[[[[[[[[[[[\n"); - uint32_t ii=0; - uint32_t iipos=0; - for(ii=0;ii<(uint32_t) iov_count;ii++) { - uint32_t jj; - for(jj=0; jj< vector[ii].iov_len; jj++) { - printf("%02x: %02x\n", jj+iipos, *((uint8_t*) (vector[ii].iov_base) +jj)); - } - iipos += vector[ii].iov_len; - } - printf("]]]]]]]]]]]]]]]]]]]]\n"); + printf("[[[[[[[[[[[[[[[[[[[[\n"); + uint32_t ii = 0; + uint32_t iipos = 0; + for (ii = 0; ii < (uint32_t) iov_count; ii++) { + uint32_t jj; + for (jj = 0; jj < vector[ii].iov_len; jj++) { + printf("%02x: %02x\n", jj + iipos, + *((uint8_t *) (vector[ii].iov_base) + jj)); + } + iipos += vector[ii].iov_len; + } + printf("]]]]]]]]]]]]]]]]]]]]\n"); #endif - if (slot_id >= private->max_slots) { - private->error = EN50221ERR_BADSLOTID; - return -1; - } - - pthread_mutex_lock(&private->slots[slot_id].slot_lock); - if (private->slots[slot_id].ca_hndl == -1) { - private->error = EN50221ERR_BADSLOTID; - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return -1; - } - if (connection_id >= private->max_connections_per_slot) { - private->error_slot = slot_id; - private->error = EN50221ERR_BADCONNECTIONID; - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return -1; - } - if (private->slots[slot_id].connections[connection_id].state != T_STATE_ACTIVE) { - private->error = EN50221ERR_BADCONNECTIONID; - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return -1; - } - - // calculate the total length of the data to send - uint32_t data_size = 0; - int i; - for(i=0; i< iov_count; i++) { - data_size += vector[i].iov_len; - } - - // allocate msg structure - struct en50221_message *msg = malloc(sizeof(struct en50221_message)+data_size+10); - if (msg == NULL) { - private->error_slot = slot_id; - private->error = EN50221ERR_OUTOFMEMORY; - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return -1; - } - - // make up data to send - int length_field_len; - msg->data[0] = T_DATA_LAST; - if ((length_field_len = asn_1_encode(data_size + 1, msg->data + 1, 3)) < 0) { - free(msg); - private->error_slot = slot_id; - private->error = EN50221ERR_ASNENCODE; - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return -1; - } - msg->data[1 + length_field_len] = connection_id; - msg->length = 1+length_field_len+1+data_size; - msg->next = NULL; - - // merge the iovecs - uint32_t pos = 1+length_field_len+1; - for(i=0; i< iov_count; i++) { - memcpy(msg->data+pos, vector[i].iov_base, vector[i].iov_len); - pos += vector[i].iov_len; - } - - // queue it for transmission - queue_message(private, slot_id, connection_id, msg); - - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return 0; + if (slot_id >= tl->max_slots) { + tl->error = EN50221ERR_BADSLOTID; + return -1; + } + + pthread_mutex_lock(&tl->slots[slot_id].slot_lock); + if (tl->slots[slot_id].ca_hndl == -1) { + tl->error = EN50221ERR_BADSLOTID; + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return -1; + } + if (connection_id >= tl->max_connections_per_slot) { + tl->error_slot = slot_id; + tl->error = EN50221ERR_BADCONNECTIONID; + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return -1; + } + if (tl->slots[slot_id].connections[connection_id].state != T_STATE_ACTIVE) { + tl->error = EN50221ERR_BADCONNECTIONID; + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return -1; + } + // calculate the total length of the data to send + uint32_t data_size = 0; + int i; + for (i = 0; i < iov_count; i++) { + data_size += vector[i].iov_len; + } + + // allocate msg structure + struct en50221_message *msg = + malloc(sizeof(struct en50221_message) + data_size + 10); + if (msg == NULL) { + tl->error_slot = slot_id; + tl->error = EN50221ERR_OUTOFMEMORY; + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return -1; + } + // make up data to send + int length_field_len; + msg->data[0] = T_DATA_LAST; + if ((length_field_len = asn_1_encode(data_size + 1, msg->data + 1, 3)) < 0) { + free(msg); + tl->error_slot = slot_id; + tl->error = EN50221ERR_ASNENCODE; + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return -1; + } + msg->data[1 + length_field_len] = connection_id; + msg->length = 1 + length_field_len + 1 + data_size; + msg->next = NULL; + + // merge the iovecs + uint32_t pos = 1 + length_field_len + 1; + for (i = 0; i < iov_count; i++) { + memcpy(msg->data + pos, vector[i].iov_base, + vector[i].iov_len); + pos += vector[i].iov_len; + } + + // queue it for transmission + queue_message(tl, slot_id, connection_id, msg); + + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return 0; } -int en50221_tl_new_tc(en50221_transport_layer tl, uint8_t slot_id) +int en50221_tl_new_tc(struct en50221_transport_layer *tl, uint8_t slot_id) { - struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl; - - // check - if (slot_id >= private->max_slots) { - private->error = EN50221ERR_BADSLOTID; - return -1; - } - - pthread_mutex_lock(&private->slots[slot_id].slot_lock); - if (private->slots[slot_id].ca_hndl == -1) { - private->error = EN50221ERR_BADSLOTID; - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return -1; - } - - // allocate a new connection if possible - int conid = en50221_tl_alloc_new_tc(private, slot_id); - if (conid == -1) { - private->error_slot = slot_id; - private->error = EN50221ERR_OUTOFCONNECTIONS; - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return -1; - } - - // allocate msg structure - struct en50221_message *msg = malloc(sizeof(struct en50221_message)+3); - if (msg == NULL) { - private->error_slot = slot_id; - private->error = EN50221ERR_OUTOFMEMORY; - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return -1; - } - - // make up the data to send - msg->data[0] = T_CREATE_T_C; - msg->data[1] = 1; - msg->data[2] = conid; - msg->length = 3; - msg->next = NULL; - - // queue it for transmission - queue_message(private, slot_id, conid, msg); - - // done - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return conid; + // check + if (slot_id >= tl->max_slots) { + tl->error = EN50221ERR_BADSLOTID; + return -1; + } + + pthread_mutex_lock(&tl->slots[slot_id].slot_lock); + if (tl->slots[slot_id].ca_hndl == -1) { + tl->error = EN50221ERR_BADSLOTID; + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return -1; + } + // allocate a new connection if possible + int conid = en50221_tl_alloc_new_tc(tl, slot_id); + if (conid == -1) { + tl->error_slot = slot_id; + tl->error = EN50221ERR_OUTOFCONNECTIONS; + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return -1; + } + // allocate msg structure + struct en50221_message *msg = + malloc(sizeof(struct en50221_message) + 3); + if (msg == NULL) { + tl->error_slot = slot_id; + tl->error = EN50221ERR_OUTOFMEMORY; + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return -1; + } + // make up the data to send + msg->data[0] = T_CREATE_T_C; + msg->data[1] = 1; + msg->data[2] = conid; + msg->length = 3; + msg->next = NULL; + + // queue it for transmission + queue_message(tl, slot_id, conid, msg); + + // done + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return conid; } -int en50221_tl_del_tc(en50221_transport_layer tl, uint8_t slot_id, uint8_t connection_id) +int en50221_tl_del_tc(struct en50221_transport_layer *tl, uint8_t slot_id, + uint8_t connection_id) { - struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl; - - // check - if (slot_id >= private->max_slots) { - private->error = EN50221ERR_BADSLOTID; - return -1; - } - - pthread_mutex_lock(&private->slots[slot_id].slot_lock); - if (private->slots[slot_id].ca_hndl == -1) { - private->error = EN50221ERR_BADSLOTID; - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return -1; - } - if (connection_id >= private->max_connections_per_slot) { - private->error_slot = slot_id; - private->error = EN50221ERR_BADCONNECTIONID; - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return -1; - } - if (!(private->slots[slot_id].connections[connection_id].state & - (T_STATE_ACTIVE|T_STATE_IN_DELETION))) { - private->error_slot = slot_id; - private->error = EN50221ERR_BADSTATE; - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return -1; - } - - // allocate msg structure - struct en50221_message *msg = malloc(sizeof(struct en50221_message)+3); - if (msg == NULL) { - private->error_slot = slot_id; - private->error = EN50221ERR_OUTOFMEMORY; - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return -1; - } - - // make up the data to send - msg->data[0] = T_DELETE_T_C; - msg->data[1] = 1; - msg->data[2] = connection_id; - msg->length = 3; - msg->next = NULL; - - // queue it for transmission - queue_message(private, slot_id, connection_id, msg); - private->slots[slot_id].connections[connection_id].state = T_STATE_ACTIVE_DELETEQUEUED; - - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return 0; + // check + if (slot_id >= tl->max_slots) { + tl->error = EN50221ERR_BADSLOTID; + return -1; + } + + pthread_mutex_lock(&tl->slots[slot_id].slot_lock); + if (tl->slots[slot_id].ca_hndl == -1) { + tl->error = EN50221ERR_BADSLOTID; + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return -1; + } + if (connection_id >= tl->max_connections_per_slot) { + tl->error_slot = slot_id; + tl->error = EN50221ERR_BADCONNECTIONID; + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return -1; + } + if (!(tl->slots[slot_id].connections[connection_id].state & + (T_STATE_ACTIVE | T_STATE_IN_DELETION))) { + tl->error_slot = slot_id; + tl->error = EN50221ERR_BADSTATE; + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return -1; + } + // allocate msg structure + struct en50221_message *msg = + malloc(sizeof(struct en50221_message) + 3); + if (msg == NULL) { + tl->error_slot = slot_id; + tl->error = EN50221ERR_OUTOFMEMORY; + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return -1; + } + // make up the data to send + msg->data[0] = T_DELETE_T_C; + msg->data[1] = 1; + msg->data[2] = connection_id; + msg->length = 3; + msg->next = NULL; + + // queue it for transmission + queue_message(tl, slot_id, connection_id, msg); + tl->slots[slot_id].connections[connection_id].state = + T_STATE_ACTIVE_DELETEQUEUED; + + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return 0; } -int en50221_tl_get_connection_state(en50221_transport_layer tl, - uint8_t slot_id, uint8_t connection_id) +int en50221_tl_get_connection_state(struct en50221_transport_layer *tl, + uint8_t slot_id, uint8_t connection_id) { - struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl; - - if (slot_id >= private->max_slots) { - private->error = EN50221ERR_BADSLOTID; - return -1; - } - - pthread_mutex_lock(&private->slots[slot_id].slot_lock); - if (private->slots[slot_id].ca_hndl == -1) { - private->error = EN50221ERR_BADSLOTID; - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return -1; - } - if (connection_id >= private->max_connections_per_slot) { - private->error_slot = slot_id; - private->error = EN50221ERR_BADCONNECTIONID; - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - return -1; - } - int state = private->slots[slot_id].connections[connection_id].state; - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - - return state; + if (slot_id >= tl->max_slots) { + tl->error = EN50221ERR_BADSLOTID; + return -1; + } + + pthread_mutex_lock(&tl->slots[slot_id].slot_lock); + if (tl->slots[slot_id].ca_hndl == -1) { + tl->error = EN50221ERR_BADSLOTID; + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return -1; + } + if (connection_id >= tl->max_connections_per_slot) { + tl->error_slot = slot_id; + tl->error = EN50221ERR_BADCONNECTIONID; + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + return -1; + } + int state = tl->slots[slot_id].connections[connection_id].state; + pthread_mutex_unlock(&tl->slots[slot_id].slot_lock); + + return state; } // ask the module for new data -static int en50221_tl_poll_tc(struct en50221_transport_layer_private *private, uint8_t slot_id, uint8_t connection_id) +static int en50221_tl_poll_tc(struct en50221_transport_layer *tl, + uint8_t slot_id, uint8_t connection_id) { - gettimeofday(&private->slots[slot_id].connections[connection_id].tx_time, 0); - - // send command - uint8_t hdr[3]; - hdr[0] = T_DATA_LAST; - hdr[1] = 1; - hdr[2] = connection_id; - if (dvbca_link_write(private->slots[slot_id].ca_hndl, private->slots[slot_id].slot, connection_id, hdr, 3) < 0) { - private->error_slot = slot_id; - private->error = EN50221ERR_CAWRITE; - return -1; - } - return 0; + gettimeofday(&tl->slots[slot_id].connections[connection_id]. + tx_time, 0); + + // send command + uint8_t hdr[3]; + hdr[0] = T_DATA_LAST; + hdr[1] = 1; + hdr[2] = connection_id; + if (dvbca_link_write(tl->slots[slot_id].ca_hndl, + tl->slots[slot_id].slot, + connection_id, hdr, 3) < 0) { + tl->error_slot = slot_id; + tl->error = EN50221ERR_CAWRITE; + return -1; + } + return 0; } // handle incoming data -static int en50221_tl_process_data(struct en50221_transport_layer_private *private, uint8_t slot_id, - uint8_t *data, uint32_t data_length) +static int en50221_tl_process_data(struct en50221_transport_layer *tl, + uint8_t slot_id, uint8_t * data, + uint32_t data_length) { - int result; + int result; #ifdef DEBUG_RXDATA - printf("-------------------\n"); - uint32_t ii=0; - for(ii=0; ii< data_length; ii++) { - printf("%02x: %02x\n", ii, data[ii]); - } - printf("+++++++++++++++++++\n"); + printf("-------------------\n"); + uint32_t ii = 0; + for (ii = 0; ii < data_length; ii++) { + printf("%02x: %02x\n", ii, data[ii]); + } + printf("+++++++++++++++++++\n"); #endif - // process the received data - while(data_length) { - // parse the header - uint8_t tpdu_tag = data[0]; - uint16_t asn_data_length; - int length_field_len; - if ((length_field_len = asn_1_decode(&asn_data_length, data + 1, data_length - 1)) < 0) { - print(LOG_LEVEL, ERROR, 1, "Received data with invalid asn from module on slot %02x\n", slot_id); - private->error_slot = slot_id; - private->error = EN50221ERR_BADCAMDATA; - return -1; - } - if ((asn_data_length < 1) || (asn_data_length > (data_length-(1+length_field_len)))) { - print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id); - private->error_slot = slot_id; - private->error = EN50221ERR_BADCAMDATA; - return -1; - } - uint8_t connection_id = data[1 + length_field_len]; - data += 1 + length_field_len + 1; - data_length -= (1 + length_field_len + 1); - asn_data_length--; - - // check the connection_id - if (connection_id >= private->max_connections_per_slot) { - print(LOG_LEVEL, ERROR, 1, "Received bad connection id %02x from module on slot %02x\n", connection_id, slot_id); - private->error_slot = slot_id; - private->error = EN50221ERR_BADCONNECTIONID; - return -1; - } - - // process the TPDUs - switch(tpdu_tag) { - case T_C_T_C_REPLY: - if ((result = en50221_tl_handle_create_tc_reply(private, slot_id, connection_id)) < 0) { - return -1; - } - break; - case T_DELETE_T_C: - if ((result = en50221_tl_handle_delete_tc(private, slot_id, connection_id)) < 0) { - return -1; - } - break; - case T_D_T_C_REPLY: - if ((result = en50221_tl_handle_delete_tc_reply(private, slot_id, connection_id)) < 0) { - return -1; - } - break; - case T_REQUEST_T_C: - if ((result = en50221_tl_handle_request_tc(private, slot_id, connection_id)) < 0) { - return -1; - } - break; - case T_DATA_MORE: - if ((result = en50221_tl_handle_data_more(private, slot_id, connection_id, data, asn_data_length)) < 0) { - return -1; - } - break; - case T_DATA_LAST: - if ((result = en50221_tl_handle_data_last(private, slot_id, connection_id, data, asn_data_length)) < 0) { - return -1; - } - break; - case T_SB: - if ((result = en50221_tl_handle_sb(private, slot_id, connection_id, data, asn_data_length)) < 0) { - return -1; - } - break; - default: - print(LOG_LEVEL, ERROR, 1, "Recieved unexpected TPDU tag %02x from module on slot %02x\n", - tpdu_tag, slot_id); - private->error_slot = slot_id; - private->error = EN50221ERR_BADCAMDATA; - return -1; - } - - // skip over the consumed data - data += asn_data_length; - data_length -= asn_data_length; - } - - return 0; + // process the received data + while (data_length) { + // parse the header + uint8_t tpdu_tag = data[0]; + uint16_t asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, data + 1, data_length - 1)) < 0) { + print(LOG_LEVEL, ERROR, 1, + "Received data with invalid asn from module on slot %02x\n", + slot_id); + tl->error_slot = slot_id; + tl->error = EN50221ERR_BADCAMDATA; + return -1; + } + if ((asn_data_length < 1) || + (asn_data_length > (data_length - (1 + length_field_len)))) { + print(LOG_LEVEL, ERROR, 1, + "Received data with invalid length from module on slot %02x\n", + slot_id); + tl->error_slot = slot_id; + tl->error = EN50221ERR_BADCAMDATA; + return -1; + } + uint8_t connection_id = data[1 + length_field_len]; + data += 1 + length_field_len + 1; + data_length -= (1 + length_field_len + 1); + asn_data_length--; + + // check the connection_id + if (connection_id >= tl->max_connections_per_slot) { + print(LOG_LEVEL, ERROR, 1, + "Received bad connection id %02x from module on slot %02x\n", + connection_id, slot_id); + tl->error_slot = slot_id; + tl->error = EN50221ERR_BADCONNECTIONID; + return -1; + } + // process the TPDUs + switch (tpdu_tag) { + case T_C_T_C_REPLY: + if ((result = en50221_tl_handle_create_tc_reply(tl, slot_id, connection_id)) < 0) { + return -1; + } + break; + case T_DELETE_T_C: + if ((result = en50221_tl_handle_delete_tc(tl, slot_id, connection_id)) < 0) { + return -1; + } + break; + case T_D_T_C_REPLY: + if ((result = en50221_tl_handle_delete_tc_reply(tl, slot_id, connection_id)) < 0) { + return -1; + } + break; + case T_REQUEST_T_C: + if ((result = en50221_tl_handle_request_tc(tl, slot_id, connection_id)) < 0) { + return -1; + } + break; + case T_DATA_MORE: + if ((result = en50221_tl_handle_data_more(tl, slot_id, + connection_id, + data, + asn_data_length)) < 0) { + return -1; + } + break; + case T_DATA_LAST: + if ((result = en50221_tl_handle_data_last(tl, slot_id, + connection_id, + data, + asn_data_length)) < 0) { + return -1; + } + break; + case T_SB: + if ((result = en50221_tl_handle_sb(tl, slot_id, + connection_id, + data, + asn_data_length)) < 0) { + return -1; + } + break; + default: + print(LOG_LEVEL, ERROR, 1, + "Recieved unexpected TPDU tag %02x from module on slot %02x\n", + tpdu_tag, slot_id); + tl->error_slot = slot_id; + tl->error = EN50221ERR_BADCAMDATA; + return -1; + } + + // skip over the consumed data + data += asn_data_length; + data_length -= asn_data_length; + } + + return 0; } -static int en50221_tl_handle_create_tc_reply(struct en50221_transport_layer_private *private, - uint8_t slot_id, uint8_t connection_id) +static int en50221_tl_handle_create_tc_reply(struct en50221_transport_layer + *tl, uint8_t slot_id, + uint8_t connection_id) { - // set this connection to state active - if (private->slots[slot_id].connections[connection_id].state == T_STATE_IN_CREATION) { - private->slots[slot_id].connections[connection_id].state = T_STATE_ACTIVE; - private->slots[slot_id].connections[connection_id].tx_time.tv_sec = 0; - - // tell upper layers - pthread_mutex_lock(&private->setcallback_lock); - en50221_tl_callback cb = private->callback; - void *cb_arg = private->callback_arg; - pthread_mutex_unlock(&private->setcallback_lock); - if (cb) - cb(cb_arg, T_CALLBACK_REASON_CONNECTIONOPEN, NULL, 0, slot_id, connection_id); - } else { - print(LOG_LEVEL, ERROR, 1, "Received T_C_T_C_REPLY for connection not in " - "T_STATE_IN_CREATION from module on slot %02x\n", slot_id); - private->error_slot = slot_id; - private->error = EN50221ERR_BADCAMDATA; - return -1; - } - - return 0; + // set this connection to state active + if (tl->slots[slot_id].connections[connection_id].state == T_STATE_IN_CREATION) { + tl->slots[slot_id].connections[connection_id].state = T_STATE_ACTIVE; + tl->slots[slot_id].connections[connection_id].tx_time.tv_sec = 0; + + // tell upper layers + pthread_mutex_lock(&tl->setcallback_lock); + en50221_tl_callback cb = tl->callback; + void *cb_arg = tl->callback_arg; + pthread_mutex_unlock(&tl->setcallback_lock); + if (cb) + cb(cb_arg, T_CALLBACK_REASON_CONNECTIONOPEN, NULL, 0, slot_id, connection_id); + } else { + print(LOG_LEVEL, ERROR, 1, + "Received T_C_T_C_REPLY for connection not in " + "T_STATE_IN_CREATION from module on slot %02x\n", + slot_id); + tl->error_slot = slot_id; + tl->error = EN50221ERR_BADCAMDATA; + return -1; + } + + return 0; } -static int en50221_tl_handle_delete_tc(struct en50221_transport_layer_private *private, - uint8_t slot_id, uint8_t connection_id) +static int en50221_tl_handle_delete_tc(struct en50221_transport_layer *tl, + uint8_t slot_id, + uint8_t connection_id) { - // immediately delete this connection and send D_T_C_REPLY - if (private->slots[slot_id].connections[connection_id].state & (T_STATE_ACTIVE|T_STATE_IN_DELETION)) - { - // clear down the slot - private->slots[slot_id].connections[connection_id].state = T_STATE_IDLE; - if (private->slots[slot_id].connections[connection_id].chain_buffer) { - free(private->slots[slot_id].connections[connection_id].chain_buffer); - } - private->slots[slot_id].connections[connection_id].chain_buffer = NULL; - private->slots[slot_id].connections[connection_id].buffer_length = 0; - - // send the reply - uint8_t hdr[3]; - hdr[0] = T_D_T_C_REPLY; - hdr[1] = 1; - hdr[2] = connection_id; - if (dvbca_link_write(private->slots[slot_id].ca_hndl, private->slots[slot_id].slot, connection_id, hdr, 3) < 0) { - private->error_slot = slot_id; - private->error = EN50221ERR_CAWRITE; - return -1; - } - - // tell upper layers - pthread_mutex_lock(&private->setcallback_lock); - en50221_tl_callback cb = private->callback; - void *cb_arg = private->callback_arg; - pthread_mutex_unlock(&private->setcallback_lock); - if (cb) - cb(cb_arg, T_CALLBACK_REASON_CONNECTIONCLOSE, NULL, 0, slot_id, connection_id); - } - else { - print(LOG_LEVEL, ERROR, 1, "Received T_DELETE_T_C for inactive connection from module on slot %02x\n", - slot_id); - private->error_slot = slot_id; - private->error = EN50221ERR_BADCAMDATA; - return -1; - } - - return 0; + // immediately delete this connection and send D_T_C_REPLY + if (tl->slots[slot_id].connections[connection_id].state & + (T_STATE_ACTIVE | T_STATE_IN_DELETION)) { + // clear down the slot + tl->slots[slot_id].connections[connection_id].state = T_STATE_IDLE; + if (tl->slots[slot_id].connections[connection_id].chain_buffer) { + free(tl->slots[slot_id].connections[connection_id].chain_buffer); + } + tl->slots[slot_id].connections[connection_id].chain_buffer = NULL; + tl->slots[slot_id].connections[connection_id].buffer_length = 0; + + // send the reply + uint8_t hdr[3]; + hdr[0] = T_D_T_C_REPLY; + hdr[1] = 1; + hdr[2] = connection_id; + if (dvbca_link_write(tl->slots[slot_id].ca_hndl, + tl->slots[slot_id].slot, + connection_id, hdr, 3) < 0) { + tl->error_slot = slot_id; + tl->error = EN50221ERR_CAWRITE; + return -1; + } + // tell upper layers + pthread_mutex_lock(&tl->setcallback_lock); + en50221_tl_callback cb = tl->callback; + void *cb_arg = tl->callback_arg; + pthread_mutex_unlock(&tl->setcallback_lock); + if (cb) + cb(cb_arg, T_CALLBACK_REASON_CONNECTIONCLOSE, NULL, 0, slot_id, connection_id); + } else { + print(LOG_LEVEL, ERROR, 1, + "Received T_DELETE_T_C for inactive connection from module on slot %02x\n", + slot_id); + tl->error_slot = slot_id; + tl->error = EN50221ERR_BADCAMDATA; + return -1; + } + + return 0; } -static int en50221_tl_handle_delete_tc_reply(struct en50221_transport_layer_private *private, - uint8_t slot_id, uint8_t connection_id) +static int en50221_tl_handle_delete_tc_reply(struct en50221_transport_layer + *tl, uint8_t slot_id, + uint8_t connection_id) { - // delete this connection, should be in T_STATE_IN_DELETION already - if (private->slots[slot_id].connections[connection_id].state == T_STATE_IN_DELETION) { - private->slots[slot_id].connections[connection_id].state = T_STATE_IDLE; - } else { - print(LOG_LEVEL, ERROR, 1, "Received T_D_T_C_REPLY received for connection not in " - "T_STATE_IN_DELETION from module on slot %02x\n", slot_id); - private->error_slot = slot_id; - private->error = EN50221ERR_BADCAMDATA; - return -1; - } - - return 0; + // delete this connection, should be in T_STATE_IN_DELETION already + if (tl->slots[slot_id].connections[connection_id].state == T_STATE_IN_DELETION) { + tl->slots[slot_id].connections[connection_id].state = T_STATE_IDLE; + } else { + print(LOG_LEVEL, ERROR, 1, + "Received T_D_T_C_REPLY received for connection not in " + "T_STATE_IN_DELETION from module on slot %02x\n", + slot_id); + tl->error_slot = slot_id; + tl->error = EN50221ERR_BADCAMDATA; + return -1; + } + + return 0; } -static int en50221_tl_handle_request_tc(struct en50221_transport_layer_private *private, - uint8_t slot_id, uint8_t connection_id) +static int en50221_tl_handle_request_tc(struct en50221_transport_layer *tl, + uint8_t slot_id, + uint8_t connection_id) { - // allocate a new connection if possible - int conid = en50221_tl_alloc_new_tc(private, slot_id); - int ca_hndl = private->slots[slot_id].ca_hndl; - if (conid == -1) { - print(LOG_LEVEL, ERROR, 1, "Too many connections requested by module on slot %02x\n", slot_id); - - // send the error - uint8_t hdr[4]; - hdr[0] = T_T_C_ERROR; - hdr[1] = 2; - hdr[2] = connection_id; - hdr[3] = 1; - if (dvbca_link_write(ca_hndl, private->slots[slot_id].slot, connection_id, hdr, 4) < 0) { - private->error_slot = slot_id; - private->error = EN50221ERR_CAWRITE; - return -1; - } - private->slots[slot_id].connections[connection_id].tx_time.tv_sec = 0; - } else { - // send the NEW_T_C on the connection we received it on - uint8_t hdr[4]; - hdr[0] = T_NEW_T_C; - hdr[1] = 2; - hdr[2] = connection_id; - hdr[3] = conid; - if (dvbca_link_write(ca_hndl, private->slots[slot_id].slot, connection_id, hdr, 4) < 0) { - private->slots[slot_id].connections[conid].state = T_STATE_IDLE; - private->error_slot = slot_id; - private->error = EN50221ERR_CAWRITE; - return -1; - } - private->slots[slot_id].connections[connection_id].tx_time.tv_sec = 0; - - // send the CREATE_T_C on the new connnection - hdr[0] = T_CREATE_T_C; - hdr[1] = 1; - hdr[2] = conid; - if (dvbca_link_write(ca_hndl, private->slots[slot_id].slot, conid, hdr, 3) < 0) { - private->slots[slot_id].connections[conid].state = T_STATE_IDLE; - private->error_slot = slot_id; - private->error = EN50221ERR_CAWRITE; - return -1; - } - gettimeofday(&private->slots[slot_id].connections[conid].tx_time, 0); - - // tell upper layers - pthread_mutex_lock(&private->setcallback_lock); - en50221_tl_callback cb = private->callback; - void *cb_arg = private->callback_arg; - pthread_mutex_unlock(&private->setcallback_lock); - if (cb) - cb(cb_arg, T_CALLBACK_REASON_CAMCONNECTIONOPEN, NULL, 0, slot_id, conid); - } - - return 0; + // allocate a new connection if possible + int conid = en50221_tl_alloc_new_tc(tl, slot_id); + int ca_hndl = tl->slots[slot_id].ca_hndl; + if (conid == -1) { + print(LOG_LEVEL, ERROR, 1, + "Too many connections requested by module on slot %02x\n", + slot_id); + + // send the error + uint8_t hdr[4]; + hdr[0] = T_T_C_ERROR; + hdr[1] = 2; + hdr[2] = connection_id; + hdr[3] = 1; + if (dvbca_link_write(ca_hndl, tl->slots[slot_id].slot, connection_id, hdr, 4) < 0) { + tl->error_slot = slot_id; + tl->error = EN50221ERR_CAWRITE; + return -1; + } + tl->slots[slot_id].connections[connection_id].tx_time. + tv_sec = 0; + } else { + // send the NEW_T_C on the connection we received it on + uint8_t hdr[4]; + hdr[0] = T_NEW_T_C; + hdr[1] = 2; + hdr[2] = connection_id; + hdr[3] = conid; + if (dvbca_link_write(ca_hndl, tl->slots[slot_id].slot, connection_id, hdr, 4) < 0) { + tl->slots[slot_id].connections[conid].state = T_STATE_IDLE; + tl->error_slot = slot_id; + tl->error = EN50221ERR_CAWRITE; + return -1; + } + tl->slots[slot_id].connections[connection_id].tx_time.tv_sec = 0; + + // send the CREATE_T_C on the new connnection + hdr[0] = T_CREATE_T_C; + hdr[1] = 1; + hdr[2] = conid; + if (dvbca_link_write(ca_hndl, tl->slots[slot_id].slot, conid, hdr, 3) < 0) { + tl->slots[slot_id].connections[conid].state = T_STATE_IDLE; + tl->error_slot = slot_id; + tl->error = EN50221ERR_CAWRITE; + return -1; + } + gettimeofday(&tl->slots[slot_id].connections[conid].tx_time, 0); + + // tell upper layers + pthread_mutex_lock(&tl->setcallback_lock); + en50221_tl_callback cb = tl->callback; + void *cb_arg = tl->callback_arg; + pthread_mutex_unlock(&tl->setcallback_lock); + if (cb) + cb(cb_arg, T_CALLBACK_REASON_CAMCONNECTIONOPEN, NULL, 0, slot_id, conid); + } + + return 0; } -static int en50221_tl_handle_data_more(struct en50221_transport_layer_private *private, - uint8_t slot_id, uint8_t connection_id, - uint8_t *data, uint32_t data_length) +static int en50221_tl_handle_data_more(struct en50221_transport_layer *tl, + uint8_t slot_id, + uint8_t connection_id, + uint8_t * data, + uint32_t data_length) { - // connection in correct state? - if (private->slots[slot_id].connections[connection_id].state != T_STATE_ACTIVE) { - print(LOG_LEVEL, ERROR, 1, "Received T_DATA_MORE for connection not in " - "T_STATE_ACTIVE from module on slot %02x\n", slot_id); - private->error_slot = slot_id; - private->error = EN50221ERR_BADCAMDATA; - return -1; - } - - // a chained data packet is coming in, save - // it to the buffer and wait for more - private->slots[slot_id].connections[connection_id].tx_time.tv_sec = 0; - int new_data_length = - private->slots[slot_id].connections[connection_id].buffer_length + data_length; - uint8_t *new_data_buffer = - realloc(private->slots[slot_id].connections[connection_id].chain_buffer, new_data_length); - if (new_data_buffer == NULL) { - private->error_slot = slot_id; - private->error = EN50221ERR_OUTOFMEMORY; - return -1; - } - private->slots[slot_id].connections[connection_id].chain_buffer = new_data_buffer; - - memcpy(private->slots[slot_id].connections[connection_id].chain_buffer + - private->slots[slot_id].connections[connection_id].buffer_length, - data, data_length); - private->slots[slot_id].connections[connection_id].buffer_length = new_data_length; - - return 0; + // connection in correct state? + if (tl->slots[slot_id].connections[connection_id].state != T_STATE_ACTIVE) { + print(LOG_LEVEL, ERROR, 1, + "Received T_DATA_MORE for connection not in " + "T_STATE_ACTIVE from module on slot %02x\n", + slot_id); + tl->error_slot = slot_id; + tl->error = EN50221ERR_BADCAMDATA; + return -1; + } + // a chained data packet is coming in, save + // it to the buffer and wait for more + tl->slots[slot_id].connections[connection_id].tx_time.tv_sec = 0; + int new_data_length = + tl->slots[slot_id].connections[connection_id].buffer_length + data_length; + uint8_t *new_data_buffer = + realloc(tl->slots[slot_id].connections[connection_id].chain_buffer, new_data_length); + if (new_data_buffer == NULL) { + tl->error_slot = slot_id; + tl->error = EN50221ERR_OUTOFMEMORY; + return -1; + } + tl->slots[slot_id].connections[connection_id].chain_buffer = new_data_buffer; + + memcpy(tl->slots[slot_id].connections[connection_id].chain_buffer + + tl->slots[slot_id].connections[connection_id].buffer_length, + data, data_length); + tl->slots[slot_id].connections[connection_id].buffer_length = new_data_length; + + return 0; } -static int en50221_tl_handle_data_last(struct en50221_transport_layer_private *private, - uint8_t slot_id, uint8_t connection_id, - uint8_t *data, uint32_t data_length) +static int en50221_tl_handle_data_last(struct en50221_transport_layer *tl, + uint8_t slot_id, + uint8_t connection_id, + uint8_t * data, + uint32_t data_length) { - // connection in correct state? - if (private->slots[slot_id].connections[connection_id].state != T_STATE_ACTIVE) { - print(LOG_LEVEL, ERROR, 1, "Received T_DATA_LAST received for connection not in " - "T_STATE_ACTIVE from module on slot %02x\n", slot_id); - private->error_slot = slot_id; - private->error = EN50221ERR_BADCAMDATA; - return -1; - } - - // last package of a chain or single package comes in - private->slots[slot_id].connections[connection_id].tx_time.tv_sec = 0; - if (private->slots[slot_id].connections[connection_id].chain_buffer == NULL) - { - // single package => dispatch immediately - pthread_mutex_lock(&private->setcallback_lock); - en50221_tl_callback cb = private->callback; - void *cb_arg = private->callback_arg; - pthread_mutex_unlock(&private->setcallback_lock); - - if (cb && data_length) { - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - cb(cb_arg, T_CALLBACK_REASON_DATA, data, data_length, slot_id, connection_id); - pthread_mutex_lock(&private->slots[slot_id].slot_lock); - } - } - else - { - int new_data_length = private->slots[slot_id].connections[connection_id].buffer_length + data_length; - uint8_t *new_data_buffer = - realloc(private->slots[slot_id].connections[connection_id].chain_buffer, new_data_length); - if (new_data_buffer == NULL) { - private->error_slot = slot_id; - private->error = EN50221ERR_OUTOFMEMORY; - return -1; - } - - memcpy(new_data_buffer + private->slots[slot_id].connections[connection_id].buffer_length, data, data_length); - - // clean the buffer position - private->slots[slot_id].connections[connection_id].chain_buffer = NULL; - private->slots[slot_id].connections[connection_id].buffer_length = 0; - - // tell the upper layers - pthread_mutex_lock(&private->setcallback_lock); - en50221_tl_callback cb = private->callback; - void *cb_arg = private->callback_arg; - pthread_mutex_unlock(&private->setcallback_lock); - if (cb && data_length) { - pthread_mutex_unlock(&private->slots[slot_id].slot_lock); - cb(cb_arg, T_CALLBACK_REASON_DATA, new_data_buffer, new_data_length, slot_id, connection_id); - pthread_mutex_lock(&private->slots[slot_id].slot_lock); - } - - free(new_data_buffer); - } - - return 0; + // connection in correct state? + if (tl->slots[slot_id].connections[connection_id].state != T_STATE_ACTIVE) { + print(LOG_LEVEL, ERROR, 1, + "Received T_DATA_LAST received for connection not in " + "T_STATE_ACTIVE from module on slot %02x\n", + slot_id); + tl->error_slot = slot_id; + tl->error = EN50221ERR_BADCAMDATA; + return -1; + } + // last package of a chain or single package comes in + tl->slots[slot_id].connections[connection_id].tx_time.tv_sec = 0; + if (tl->slots[slot_id].connections[connection_id].chain_buffer == NULL) { + // single package => dispatch immediately + pthread_mutex_lock(&tl->setcallback_lock); + en50221_tl_callback cb = tl->callback; + void *cb_arg = tl->callback_arg; + pthread_mutex_unlock(&tl->setcallback_lock); + + if (cb && data_length) { + pthread_mutex_unlock(&tl->slots[slot_id]. + slot_lock); + cb(cb_arg, T_CALLBACK_REASON_DATA, data, data_length, slot_id, connection_id); + pthread_mutex_lock(&tl->slots[slot_id].slot_lock); + } + } else { + int new_data_length = + tl->slots[slot_id].connections[connection_id].buffer_length + data_length; + uint8_t *new_data_buffer = + realloc(tl->slots[slot_id].connections[connection_id].chain_buffer, new_data_length); + if (new_data_buffer == NULL) { + tl->error_slot = slot_id; + tl->error = EN50221ERR_OUTOFMEMORY; + return -1; + } + + memcpy(new_data_buffer + + tl->slots[slot_id].connections[connection_id]. + buffer_length, data, data_length); + + // clean the buffer position + tl->slots[slot_id].connections[connection_id].chain_buffer = NULL; + tl->slots[slot_id].connections[connection_id].buffer_length = 0; + + // tell the upper layers + pthread_mutex_lock(&tl->setcallback_lock); + en50221_tl_callback cb = tl->callback; + void *cb_arg = tl->callback_arg; + pthread_mutex_unlock(&tl->setcallback_lock); + if (cb && data_length) { + pthread_mutex_unlock(&tl->slots[slot_id]. + slot_lock); + cb(cb_arg, T_CALLBACK_REASON_DATA, new_data_buffer, + new_data_length, slot_id, connection_id); + pthread_mutex_lock(&tl->slots[slot_id].slot_lock); + } + + free(new_data_buffer); + } + + return 0; } -static int en50221_tl_handle_sb(struct en50221_transport_layer_private *private, - uint8_t slot_id, uint8_t connection_id, - uint8_t *data, uint32_t data_length) +static int en50221_tl_handle_sb(struct en50221_transport_layer *tl, + uint8_t slot_id, uint8_t connection_id, + uint8_t * data, uint32_t data_length) { - // is the connection id ok? - if (private->slots[slot_id].connections[connection_id].state != T_STATE_ACTIVE) { - print(LOG_LEVEL, ERROR, 1, "Received T_SB for connection not in T_STATE_ACTIVE from module on slot %02x\n", - slot_id); - private->error_slot = slot_id; - private->error = EN50221ERR_BADCAMDATA; - return -1; - } - - // did we get enough data in the T_SB? - if (data_length != 1) { - print(LOG_LEVEL, ERROR, 1, "Recieved T_SB with invalid length from module on slot %02x\n", slot_id); - private->error_slot = slot_id; - private->error = EN50221ERR_BADCAMDATA; - return -1; - } - - // tell it to send the data if it says there is some - if (data[0] & 0x80) { - int ca_hndl = private->slots[slot_id].ca_hndl; - - // send the RCV - uint8_t hdr[3]; - hdr[0] = T_RCV; - hdr[1] = 1; - hdr[2] = connection_id; - if (dvbca_link_write(ca_hndl, private->slots[slot_id].slot, connection_id, hdr, 3) < 0) { - private->error_slot = slot_id; - private->error = EN50221ERR_CAWRITE; - return -1; - } - gettimeofday(&private->slots[slot_id].connections[connection_id].tx_time, 0); - - } else { - // no data - indicate not waiting for anything now - private->slots[slot_id].connections[connection_id].tx_time.tv_sec = 0; - } - - return 0; + // is the connection id ok? + if (tl->slots[slot_id].connections[connection_id].state != T_STATE_ACTIVE) { + print(LOG_LEVEL, ERROR, 1, + "Received T_SB for connection not in T_STATE_ACTIVE from module on slot %02x\n", + slot_id); + tl->error_slot = slot_id; + tl->error = EN50221ERR_BADCAMDATA; + return -1; + } + // did we get enough data in the T_SB? + if (data_length != 1) { + print(LOG_LEVEL, ERROR, 1, + "Recieved T_SB with invalid length from module on slot %02x\n", + slot_id); + tl->error_slot = slot_id; + tl->error = EN50221ERR_BADCAMDATA; + return -1; + } + // tell it to send the data if it says there is some + if (data[0] & 0x80) { + int ca_hndl = tl->slots[slot_id].ca_hndl; + + // send the RCV + uint8_t hdr[3]; + hdr[0] = T_RCV; + hdr[1] = 1; + hdr[2] = connection_id; + if (dvbca_link_write(ca_hndl, tl->slots[slot_id].slot, connection_id, hdr, 3) < 0) { + tl->error_slot = slot_id; + tl->error = EN50221ERR_CAWRITE; + return -1; + } + gettimeofday(&tl->slots[slot_id].connections[connection_id].tx_time, 0); + + } else { + // no data - indicate not waiting for anything now + tl->slots[slot_id].connections[connection_id].tx_time.tv_sec = 0; + } + + return 0; } -static int en50221_tl_alloc_new_tc(struct en50221_transport_layer_private *private, uint8_t slot_id) +static int en50221_tl_alloc_new_tc(struct en50221_transport_layer *tl, + uint8_t slot_id) { - // we browse through the array of connection - // types, to look for the first unused one - int i, conid = -1; - for(i=1; i < private->max_connections_per_slot; i++) { - if (private->slots[slot_id].connections[i].state == T_STATE_IDLE) { - conid = i; - break; - } - } - if (conid == -1) { - print(LOG_LEVEL, ERROR, 1, "CREATE_T_C failed: no more connections available\n"); - return -1; - } - - // set up the connection struct - private->slots[slot_id].connections[conid].state = T_STATE_IN_CREATION; - private->slots[slot_id].connections[conid].chain_buffer = NULL; - private->slots[slot_id].connections[conid].buffer_length = 0; - - return conid; + // we browse through the array of connection + // types, to look for the first unused one + int i, conid = -1; + for (i = 1; i < tl->max_connections_per_slot; i++) { + if (tl->slots[slot_id].connections[i].state == T_STATE_IDLE) { + conid = i; + break; + } + } + if (conid == -1) { + print(LOG_LEVEL, ERROR, 1, + "CREATE_T_C failed: no more connections available\n"); + return -1; + } + // set up the connection struct + tl->slots[slot_id].connections[conid].state = T_STATE_IN_CREATION; + tl->slots[slot_id].connections[conid].chain_buffer = NULL; + tl->slots[slot_id].connections[conid].buffer_length = 0; + + return conid; } -static void queue_message(struct en50221_transport_layer_private *private, uint8_t slot_id, - uint8_t connection_id, struct en50221_message *msg) +static void queue_message(struct en50221_transport_layer *tl, + uint8_t slot_id, uint8_t connection_id, + struct en50221_message *msg) { - msg->next = NULL; - if (private->slots[slot_id].connections[connection_id].send_queue_tail) { - private->slots[slot_id].connections[connection_id].send_queue_tail->next = msg; - } else { - private->slots[slot_id].connections[connection_id].send_queue = msg; - private->slots[slot_id].connections[connection_id].send_queue_tail = msg; - } + msg->next = NULL; + if (tl->slots[slot_id].connections[connection_id].send_queue_tail) { + tl->slots[slot_id].connections[connection_id].send_queue_tail->next = msg; + tl->slots[slot_id].connections[connection_id].send_queue_tail = msg; + } else { + tl->slots[slot_id].connections[connection_id].send_queue = msg; + tl->slots[slot_id].connections[connection_id].send_queue_tail = msg; + } } diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_transport.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_transport.h index e1dd1c5..7882060 100644 --- a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_transport.h +++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_transport.h @@ -2,7 +2,7 @@ en50221 encoder An implementation for libdvb an implementation for the en50221 session layer - Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com> Copyright (C) 2005 Julian Scheel (julian at jusst dot de) Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) @@ -18,7 +18,7 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -26,8 +26,7 @@ #define __EN50221_TRANSPORT_H__ #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif #include <stdlib.h> @@ -37,23 +36,23 @@ extern "C" /** * Callback reasons. */ -#define T_CALLBACK_REASON_CONNECTIONOPEN 0x00 // A connection we opened _to_ the cam has been ACKed -#define T_CALLBACK_REASON_CAMCONNECTIONOPEN 0x01 // The cam has opened a connection to _us_. -#define T_CALLBACK_REASON_DATA 0x02 // Data received -#define T_CALLBACK_REASON_CONNECTIONCLOSE 0x03 // The cam has told us to close a connection. -#define T_CALLBACK_REASON_SLOTCLOSE 0x04 // The cam in the supplied slot id has been removed. +#define T_CALLBACK_REASON_CONNECTIONOPEN 0x00 // A connection we opened _to_ the cam has been ACKed +#define T_CALLBACK_REASON_CAMCONNECTIONOPEN 0x01 // The cam has opened a connection to _us_. +#define T_CALLBACK_REASON_DATA 0x02 // Data received +#define T_CALLBACK_REASON_CONNECTIONCLOSE 0x03 // The cam has told us to close a connection. +#define T_CALLBACK_REASON_SLOTCLOSE 0x04 // The cam in the supplied slot id has been removed. // these are the states a TC can be in -#define T_STATE_IDLE 0x01 // this transport connection is not in use -#define T_STATE_ACTIVE 0x02 // this transport connection is in use -#define T_STATE_ACTIVE_DELETEQUEUED 0x04 // this transport connection is about to be deleted -#define T_STATE_IN_CREATION 0x08 // this transport waits for a T_C_T_C_REPLY to become active -#define T_STATE_IN_DELETION 0x10 // this transport waits for T_D_T_C_REPLY to become idle again +#define T_STATE_IDLE 0x01 // this transport connection is not in use +#define T_STATE_ACTIVE 0x02 // this transport connection is in use +#define T_STATE_ACTIVE_DELETEQUEUED 0x04 // this transport connection is about to be deleted +#define T_STATE_IN_CREATION 0x08 // this transport waits for a T_C_T_C_REPLY to become active +#define T_STATE_IN_DELETION 0x10 // this transport waits for T_D_T_C_REPLY to become idle again /** * Opaque type representing a transport layer. */ -typedef void *en50221_transport_layer; +struct en50221_transport_layer; /** * Type definition for callback function - used when events are received from a module. @@ -72,9 +71,11 @@ typedef void *en50221_transport_layer; * @param slot_id Slot_id the data was received from. * @param connection_id Connection_id the data was received from. */ -typedef void (*en50221_tl_callback)(void *arg, int reason, - uint8_t *data, uint32_t data_length, - uint8_t slot_id, uint8_t connection_id); +typedef void (*en50221_tl_callback) (void *arg, int reason, + uint8_t * data, + uint32_t data_length, + uint8_t slot_id, + uint8_t connection_id); /** @@ -84,14 +85,15 @@ typedef void (*en50221_tl_callback)(void *arg, int reason, * @param max_connections_per_slot Maximum connections per slot. * @return The en50221_transport_layer instance, or NULL on error. */ -extern en50221_transport_layer en50221_tl_create(uint8_t max_slots, uint8_t max_connections_per_slot); +extern struct en50221_transport_layer *en50221_tl_create(uint8_t max_slots, + uint8_t max_connections_per_slot); /** * Destroy an instance of the transport layer. * * @param tl The en50221_transport_layer instance. */ -extern void en50221_tl_destroy(en50221_transport_layer tl); +extern void en50221_tl_destroy(struct en50221_transport_layer *tl); /** * Register a new slot with the library. @@ -103,9 +105,10 @@ extern void en50221_tl_destroy(en50221_transport_layer tl); * @param poll_delay Interval between polls in ms. * @return slot_id on sucess, or -1 on error. */ -extern int en50221_tl_register_slot(en50221_transport_layer tl, int ca_hndl, - uint8_t slot, uint32_t response_timeout, - uint32_t poll_delay); +extern int en50221_tl_register_slot(struct en50221_transport_layer *tl, + int ca_hndl, uint8_t slot, + uint32_t response_timeout, + uint32_t poll_delay); /** * Destroy a registered slot - e.g. if a CAM is removed, or an error occurs. Does @@ -114,7 +117,7 @@ extern int en50221_tl_register_slot(en50221_transport_layer tl, int ca_hndl, * @param tl The en50221_transport_layer instance. * @param slot_id Slot to destroy. */ -extern void en50221_tl_destroy_slot(en50221_transport_layer tl, uint8_t slot_id); +extern void en50221_tl_destroy_slot(struct en50221_transport_layer *tl, uint8_t slot_id); /** * Performs one iteration of the transport layer poll - @@ -126,7 +129,7 @@ extern void en50221_tl_destroy_slot(en50221_transport_layer tl, uint8_t slot_id) * @param tl The en50221_transport_layer instance. * @return 0 on succes, or -1 if there was an error of some sort. */ -extern int en50221_tl_poll(en50221_transport_layer tl); +extern int en50221_tl_poll(struct en50221_transport_layer *tl); /** * Register the callback for data reception. @@ -135,8 +138,8 @@ extern int en50221_tl_poll(en50221_transport_layer tl); * @param callback The callback. Set to NULL to remove the callback completely. * @param arg Private data passed as arg0 of the callback. */ -extern void en50221_tl_register_callback(en50221_transport_layer tl, - en50221_tl_callback callback, void *arg); +extern void en50221_tl_register_callback(struct en50221_transport_layer *tl, + en50221_tl_callback callback, void *arg); /** * Gets the ID of the slot an error occurred on. @@ -144,7 +147,7 @@ extern void en50221_tl_register_callback(en50221_transport_layer tl, * @param tl The en50221_transport_layer instance. * @return The offending slot id. */ -extern int en50221_tl_get_error_slot(en50221_transport_layer tl); +extern int en50221_tl_get_error_slot(struct en50221_transport_layer *tl); /** * Gets the last error. @@ -152,7 +155,7 @@ extern int en50221_tl_get_error_slot(en50221_transport_layer tl); * @param tl The en50221_transport_layer instance. * @return One of the EN50221ERR_* values. */ -extern int en50221_tl_get_error(en50221_transport_layer tl); +extern int en50221_tl_get_error(struct en50221_transport_layer *tl); /** * This function is used to take a data-block, pack into @@ -165,9 +168,11 @@ extern int en50221_tl_get_error(en50221_transport_layer tl); * @param data_length Number of bytes to send. * @return 0 on success, or -1 on error. */ -extern int en50221_tl_send_data(en50221_transport_layer tl, - uint8_t slot_id, uint8_t connection_id, - uint8_t *data, uint32_t data_length); +extern int en50221_tl_send_data(struct en50221_transport_layer *tl, + uint8_t slot_id, + uint8_t connection_id, + uint8_t * data, + uint32_t data_length); /** * This function is used to take a data-block, pack into @@ -180,9 +185,9 @@ extern int en50221_tl_send_data(en50221_transport_layer tl, * @param io_count Number of elements in vector. * @return 0 on success, or -1 on error. */ -extern int en50221_tl_send_datav(en50221_transport_layer tl, uint8_t slot_id, - uint8_t connection_id, struct iovec *vector, - int iov_count); +extern int en50221_tl_send_datav(struct en50221_transport_layer *tl, + uint8_t slot_id, uint8_t connection_id, + struct iovec *vector, int iov_count); /** * Create a new transport connection to the cam. @@ -196,7 +201,7 @@ extern int en50221_tl_send_datav(en50221_transport_layer tl, uint8_t slot_id, * @param slot_id ID of the slot. * @return The allocated connection id on success, or -1 on error. */ -extern int en50221_tl_new_tc(en50221_transport_layer tl, uint8_t slot_id); +extern int en50221_tl_new_tc(struct en50221_transport_layer *tl, uint8_t slot_id); /** * Deallocates a transport connection. @@ -210,8 +215,7 @@ extern int en50221_tl_new_tc(en50221_transport_layer tl, uint8_t slot_id); * @param connection_id Connection id to send the request _on_. * @return 0 on success, or -1 on error. */ -extern int en50221_tl_del_tc(en50221_transport_layer tl, uint8_t slot_id, - uint8_t connection_id); +extern int en50221_tl_del_tc(struct en50221_transport_layer *tl, uint8_t slot_id, uint8_t connection_id); /** * Checks the state of a connection. @@ -221,11 +225,10 @@ extern int en50221_tl_del_tc(en50221_transport_layer tl, uint8_t slot_id, * @param connection_id Connection id to send the request _on_. * @return One of the T_STATE_* values. */ -extern int en50221_tl_get_connection_state(en50221_transport_layer tl, - uint8_t slot_id, uint8_t connection_id); +extern int en50221_tl_get_connection_state(struct en50221_transport_layer *tl, + uint8_t slot_id, uint8_t connection_id); #ifdef __cplusplus } #endif - #endif diff --git a/kaffeine/src/input/dvb/lib/libdvbmisc/dvbmisc.h b/kaffeine/src/input/dvb/lib/libdvbmisc/dvbmisc.h index 75713f4..8ac6eee 100644 --- a/kaffeine/src/input/dvb/lib/libdvbmisc/dvbmisc.h +++ b/kaffeine/src/input/dvb/lib/libdvbmisc/dvbmisc.h @@ -1,7 +1,7 @@ /* libdvbmisc - DVB miscellaneous library - Copyright (C) 2005 Manu Abraham <manu@kromtek.com> + Copyright (C) 2005 Manu Abraham <abraham.manu@gmail.com> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/kaffeine/src/input/dvb/lib/libucsi/Makefile.am b/kaffeine/src/input/dvb/lib/libucsi/Makefile.am index 071f310..36f905e 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/Makefile.am +++ b/kaffeine/src/input/dvb/lib/libucsi/Makefile.am @@ -1,6 +1,6 @@ noinst_LTLIBRARIES = libucsi.la -SUBDIRS = dvb mpeg . +SUBDIRS = dvb mpeg atsc . INCLUDES = -I$(top_srcdir)/kaffeine/src/input/dvb/lib @@ -9,9 +9,11 @@ libucsi_la_SOURCES = crc32.c \ transport_packet.c libucsi_la_LDFLAGS = ./mpeg \ - ./dvb + ./dvb \ + /atsc libucsi_la_LIBADD = ./mpeg/libdvbmpeg.la \ - ./dvb/libdvbdvb.la + ./dvb/libdvbdvb.la \ + ./atsc/libdvbatsc.la CFLAGS = -g -O2 -Wall -Wshadow -Wpointer-arith -Wstrict-prototypes -fPIC diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/Makefile.am b/kaffeine/src/input/dvb/lib/libucsi/atsc/Makefile.am new file mode 100644 index 0000000..2df5d3b --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/Makefile.am @@ -0,0 +1,17 @@ +noinst_LTLIBRARIES = libdvbatsc.la + +INCLUDES = -I$(top_srcdir)/kaffeine/src/input/dvb/lib + +libdvbatsc_la_SOURCES = atsc_text.c \ + cvct_section.c \ + dccsct_section.c \ + dcct_section.c \ + eit_section.c \ + ett_section.c \ + mgt_section.c \ + rrt_section.c \ + stt_section.c \ + tvct_section.c \ + types.c + +CFLAGS = -g -O2 -Wall -Wshadow -Wpointer-arith -Wstrict-prototypes -fPIC diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/ac3_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/atsc/ac3_descriptor.h new file mode 100644 index 0000000..489695b --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/ac3_descriptor.h @@ -0,0 +1,112 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_atsc@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_ATSC_AC3_DESCRIPTOR +#define _UCSI_ATSC_AC3_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +enum atsc_ac3_channels { + ATSC_AC3_CHANNELS_1_PLUS_1 = 0x0, + ATSC_AC3_CHANNELS_1_0 = 0x1, + ATSC_AC3_CHANNELS_2_0 = 0x2, + ATSC_AC3_CHANNELS_3_0 = 0x3, + ATSC_AC3_CHANNELS_2_1 = 0x4, + ATSC_AC3_CHANNELS_3_1 = 0x5, + ATSC_AC3_CHANNELS_2_2 = 0x6, + ATSC_AC3_CHANNELS_3_2 = 0x7, + ATSC_AC3_CHANNELS_1 = 0x8, + ATSC_AC3_CHANNELS_LTEQ_2 = 0x9, + ATSC_AC3_CHANNELS_LTEQ_3 = 0xa, + ATSC_AC3_CHANNELS_LTEQ_4 = 0xb, + ATSC_AC3_CHANNELS_LTEQ_5 = 0xc, + ATSC_AC3_CHANNELS_LTEQ_6 = 0xd, +}; + +/** + * atsc_ac3_descriptor structure. + */ +struct atsc_ac3_descriptor { + struct descriptor d; + + EBIT2(uint8_t sample_rate_code : 3; , + uint8_t bsid : 5; ); + EBIT2(uint8_t bit_rate_code : 6; , + uint8_t surround_mode : 2; ); + EBIT3(uint8_t bsmod : 3; , + uint8_t num_channels : 4; , + uint8_t full_svc : 1; ); + /* uint8_t additional_info[] */ +} __ucsi_packed; + +/** + * Process an atsc_ac3_descriptor. + * + * @param d Generic descriptor structure. + * @return atsc_ac3_descriptor pointer, or NULL on error. + */ +static inline struct atsc_ac3_descriptor* + atsc_ac3_descriptor_codec(struct descriptor* d) +{ + int pos = 0; + + if (d->len < (pos+4)) + return NULL; + pos += 4; + + return (struct atsc_ac3_descriptor*) d; +} + +/** + * Retrieve pointer to additional_info field of a atsc_ac3_descriptor. + * + * @param d atsc_ac3_descriptor pointer. + * @return Pointer to additional_info field. + */ +static inline uint8_t *atsc_ac3_descriptor_additional_info(struct atsc_ac3_descriptor *d) +{ + int pos = sizeof(struct atsc_ac3_descriptor); + + return ((uint8_t *) d) + pos; +} + +/** + * Determine length of additional_info field of a atsc_ac3_descriptor. + * + * @param d atsc_ac3_descriptor pointer. + * @return Length of field in bytes. + */ +static inline int atsc_ac3_descriptor_additional_info_length(struct atsc_ac3_descriptor* d) +{ + return d->d.len - 3; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/atsc_text.c b/kaffeine/src/input/dvb/lib/libucsi/atsc/atsc_text.c new file mode 100644 index 0000000..d79c83f --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/atsc_text.c @@ -0,0 +1,743 @@ +/* +* section and descriptor parser +* +* Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +*/ + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include "libucsi/endianops.h" +#include "libucsi/atsc/types.h" + +#define HUFFTREE_LITERAL_MASK 0x80 +#define HUFFSTRING_END 0x00 +#define HUFFSTRING_ESCAPE 0x1b + +#define DEST_ALLOC_DELTA 20 + +struct hufftree_entry { + uint8_t left_idx; + uint8_t right_idx; +} __ucsi_packed; + +struct huffbuff { + uint8_t *buf; + uint32_t buf_len; + + uint32_t cur_byte; + uint8_t cur_bit; +}; + + +static struct hufftree_entry program_description_hufftree[][128] = { + { {0x14, 0x15}, {0x9b, 0xd6}, {0xc9, 0xcf}, {0xd7, 0xc7}, {0x01, 0xa2}, + {0xce, 0xcb}, {0x02, 0x03}, {0xc5, 0xcc}, {0xc6, 0xc8}, {0x04, 0xc4}, + {0x05, 0xc2}, {0x06, 0xc3}, {0xd2, 0x07}, {0xd3, 0x08}, {0xca, 0xd4}, + {0x09, 0xcd}, {0xd0, 0x0a}, {0xc1, 0x0b}, {0x0c, 0x0d}, {0x0e, 0x0f}, + {0x10, 0x11}, {0x12, 0x13}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x38, 0x39}, {0xad, 0xaf}, {0xb7, 0xda}, {0xa8, 0xb3}, {0xb5, 0x01}, + {0x02, 0x9b}, {0xb4, 0xf1}, {0xa2, 0xd5}, {0xd6, 0xd9}, {0x03, 0x04}, + {0x05, 0xcf}, {0x06, 0xc9}, {0xf9, 0xea}, {0xeb, 0xf5}, {0xf6, 0x07}, + {0x08, 0x09}, {0xb2, 0xc5}, {0xc6, 0xb1}, {0x0a, 0xee}, {0xcb, 0x0b}, + {0xd4, 0x0c}, {0xc4, 0xc8}, {0xd2, 0x0d}, {0x0e, 0x0f}, {0xc7, 0xca}, + {0xce, 0xd0}, {0xd7, 0x10}, {0xc2, 0x11}, {0xcc, 0xec}, {0xe5, 0xe7}, + {0x12, 0xcd}, {0x13, 0x14}, {0xc3, 0x15}, {0x16, 0x17}, {0xed, 0x18}, + {0x19, 0xf2}, {0x1a, 0xd3}, {0x1b, 0x1c}, {0xe4, 0x1d}, {0xc1, 0xe3}, + {0x1e, 0xe9}, {0xf0, 0xe2}, {0xf7, 0x1f}, {0xf3, 0xe6}, {0x20, 0x21}, + {0x22, 0xe8}, {0xef, 0x23}, {0x24, 0x25}, {0x26, 0x27}, {0x28, 0x29}, + {0x2a, 0xf4}, {0x2b, 0x2c}, {0x2d, 0x2e}, {0x2f, 0xe1}, {0x30, 0x31}, + {0x32, 0x33}, {0x34, 0x35}, {0x36, 0x37}, }, + { {0x9b, 0x9b}, }, + { {0x03, 0x04}, {0x80, 0xae}, {0xc8, 0xd4}, {0x01, 0x02}, {0x9b, 0xa0}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x02, 0xf3}, {0xa0, 0xf4}, {0x9b, 0x01}, }, + { {0x9b, 0x9b}, }, + { {0xac, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x01, 0xa0}, {0x9b, 0xa2}, }, + { {0x07, 0x08}, {0xe2, 0xe4}, {0xe5, 0xe6}, {0xa0, 0xf2}, {0xe1, 0x01}, + {0x02, 0xf3}, {0xe3, 0x03}, {0x04, 0x05}, {0x9b, 0x06}, }, + { {0x04, 0x80}, {0xca, 0xd3}, {0xa2, 0x01}, {0x9b, 0x02}, {0x03, 0xa0}, }, + { {0x9b, 0xa0}, }, + { {0x03, 0x04}, {0x9b, 0xb7}, {0xf4, 0xa0}, {0xb0, 0xf3}, {0x01, 0x02}, }, + { {0xb9, 0x02}, {0xb8, 0x9b}, {0xa0, 0x01}, }, + { {0xae, 0x02}, {0xb6, 0x9b}, {0x01, 0xa0}, }, + { {0xa0, 0x01}, {0x9b, 0xb0}, }, + { {0xae, 0x01}, {0x9b, 0xa0}, }, + { {0xae, 0x01}, {0xa0, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x01}, {0xac, 0xae}, }, + { {0x9b, 0x9b}, }, + { {0x02, 0x03}, {0x9b, 0xa0}, {0xb5, 0xb6}, {0xb8, 0x01}, }, + { {0x9b, 0xa0}, }, + { {0x9b, 0xa0}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0xa0}, }, + { {0x9b, 0x9b}, }, + { {0x08, 0x09}, {0xe6, 0xf5}, {0xf3, 0xf4}, {0x9b, 0xe4}, {0x01, 0xed}, + {0x02, 0x03}, {0x04, 0xf2}, {0x05, 0x06}, {0xec, 0xee}, {0x07, 0xa0}, }, + { {0x05, 0x06}, {0x9b, 0xec}, {0xf5, 0x01}, {0x02, 0xe1}, {0xef, 0xe5}, + {0xe9, 0xf2}, {0x03, 0x04}, }, + { {0x06, 0x07}, {0x9b, 0xe9}, {0xf9, 0xf2}, {0xf5, 0x01}, {0x02, 0x03}, + {0xec, 0xef}, {0xe1, 0x04}, {0xe8, 0x05}, }, + { {0x05, 0x06}, {0xf9, 0xf2}, {0xf5, 0x9b}, {0xe5, 0xef}, {0x01, 0x02}, + {0xe9, 0xe1}, {0x03, 0x04}, }, + { {0x06, 0x07}, {0xe1, 0xe9}, {0xee, 0xf6}, {0xe4, 0xec}, {0xf3, 0x01}, + {0x02, 0xf2}, {0x03, 0x04}, {0x9b, 0x05}, }, + { {0x02, 0x03}, {0xe5, 0xec}, {0x9b, 0xef}, {0x01, 0xf2}, }, + { {0x05, 0x06}, {0xf5, 0xef}, {0x9b, 0xec}, {0xe9, 0x01}, {0xe1, 0xf2}, + {0x02, 0xe5}, {0x03, 0x04}, }, + { {0x03, 0x04}, {0x9b, 0xe5}, {0xe9, 0xf5}, {0xe1, 0x01}, {0xef, 0x02}, }, + { {0x04, 0x05}, {0xa0, 0xc9}, {0xf3, 0x9b}, {0xae, 0xf2}, {0x01, 0x02}, + {0x03, 0xee}, }, + { {0xef, 0x05}, {0x9b, 0xae}, {0xe9, 0xe5}, {0x01, 0xf5}, {0x02, 0xe1}, + {0x03, 0x04}, }, + { {0xe5, 0x03}, {0xe1, 0xe9}, {0xf2, 0x9b}, {0x01, 0x02}, }, + { {0x03, 0x04}, {0x9b, 0xe9}, {0xf5, 0x01}, {0xe5, 0x02}, {0xef, 0xe1}, }, + { {0xe1, 0x05}, {0x9b, 0xe3}, {0xef, 0x01}, {0xf5, 0xe5}, {0x02, 0x03}, + {0xe9, 0x04}, }, + { {0xe5, 0x03}, {0x9b, 0xe9}, {0x01, 0xe1}, {0xef, 0x02}, }, + { {0x03, 0x04}, {0xa7, 0xee}, {0xec, 0xf2}, {0xf3, 0x01}, {0x9b, 0x02}, }, + { {0xe1, 0x06}, {0x9b, 0xe8}, {0xe9, 0x01}, {0xf2, 0xec}, {0x02, 0xef}, + {0x03, 0xe5}, {0x04, 0x05}, }, + { {0x9b, 0x9b}, }, + { {0x03, 0x04}, {0x9b, 0xae}, {0x01, 0xe9}, {0x02, 0xe1}, {0xe5, 0xef}, }, + { {0x09, 0x0a}, {0xf6, 0xf9}, {0x01, 0xae}, {0xe3, 0xe9}, {0xf5, 0x9b}, + {0xe5, 0xef}, {0x02, 0x03}, {0xe1, 0x04}, {0xe8, 0x05}, {0x06, 0xf4}, + {0x07, 0x08}, }, + { {0xe8, 0x07}, {0xe5, 0xf7}, {0xd6, 0xe1}, {0x9b, 0xe9}, {0xf2, 0x01}, + {0x02, 0x03}, {0x04, 0xef}, {0x05, 0x06}, }, + { {0xae, 0x01}, {0x9b, 0xee}, }, + { {0xe9, 0x02}, {0xe5, 0x9b}, {0xa0, 0x01}, }, + { {0x03, 0x04}, {0x9b, 0xe8}, {0xe5, 0xe1}, {0xef, 0x01}, {0xe9, 0x02}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0xef}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x18, 0x19}, {0xe8, 0xef}, {0xf8, 0x9b}, {0xa7, 0xf7}, {0xfa, 0x01}, + {0x02, 0x03}, {0x04, 0xe5}, {0xae, 0x05}, {0xe6, 0xe2}, {0x06, 0xf6}, + {0xeb, 0xf5}, {0xe9, 0x07}, {0xf0, 0xf9}, {0xe7, 0x08}, {0x09, 0xe4}, + {0x0a, 0xe3}, {0x0b, 0xed}, {0x0c, 0xf3}, {0x0d, 0x0e}, {0x0f, 0xec}, + {0x10, 0xf4}, {0x11, 0x12}, {0xf2, 0xa0}, {0x13, 0x14}, {0x15, 0xee}, + {0x16, 0x17}, }, + { {0x0b, 0x0c}, {0xe4, 0xf3}, {0x9b, 0xae}, {0xe2, 0x01}, {0x02, 0x03}, + {0xec, 0xa0}, {0x04, 0xe9}, {0xf2, 0xf5}, {0x05, 0xf9}, {0xe1, 0x06}, + {0xef, 0x07}, {0xe5, 0x08}, {0x09, 0x0a}, }, + { {0x0f, 0x10}, {0xf1, 0xae}, {0xc4, 0xf9}, {0xac, 0x01}, {0xe3, 0x02}, + {0x9b, 0xf2}, {0x03, 0x04}, {0xa0, 0xec}, {0xf5, 0x05}, {0x06, 0xe9}, + {0x07, 0xeb}, {0x08, 0xf4}, {0x09, 0xe5}, {0x0a, 0xef}, {0xe1, 0xe8}, + {0x0b, 0x0c}, {0x0d, 0x0e}, }, + { {0x13, 0x14}, {0xa7, 0xbb}, {0xe6, 0xed}, {0xf7, 0xe7}, {0xf6, 0x01}, + {0x02, 0x9b}, {0xee, 0x03}, {0x04, 0xec}, {0x05, 0xf5}, {0x06, 0xac}, + {0xe4, 0xf9}, {0xf2, 0x07}, {0x08, 0x09}, {0xae, 0x0a}, {0xef, 0x0b}, + {0xe1, 0xf3}, {0x0c, 0xe9}, {0x0d, 0x0e}, {0x0f, 0x10}, {0xe5, 0x11}, + {0x12, 0xa0}, }, + { {0x1d, 0x1e}, {0xa9, 0xe8}, {0xf5, 0x9b}, {0x01, 0xad}, {0xbb, 0xeb}, + {0xfa, 0x02}, {0xa7, 0xe6}, {0xe2, 0xe7}, {0x03, 0x04}, {0x05, 0x06}, + {0xe9, 0xf8}, {0x07, 0xac}, {0xef, 0xf0}, {0x08, 0xed}, {0xf6, 0xf9}, + {0x09, 0xf7}, {0x0a, 0x0b}, {0xae, 0x0c}, {0xe3, 0x0d}, {0xe5, 0xf4}, + {0x0e, 0x0f}, {0xe4, 0x10}, {0xec, 0x11}, {0xe1, 0x12}, {0x13, 0x14}, + {0x15, 0x16}, {0xee, 0xf3}, {0x17, 0x18}, {0xf2, 0xa0}, {0x19, 0x1a}, + {0x1b, 0x1c}, }, + { {0x09, 0x0a}, {0xae, 0x9b}, {0xec, 0x01}, {0xf5, 0x02}, {0xf4, 0xe6}, + {0x03, 0xe1}, {0xe5, 0xe9}, {0x04, 0xf2}, {0xef, 0x05}, {0x06, 0x07}, + {0xa0, 0x08}, }, + { {0x0e, 0x0f}, {0xad, 0xe7}, {0x9b, 0xa7}, {0xf9, 0x01}, {0xec, 0x02}, + {0xac, 0xf2}, {0x03, 0xae}, {0xf3, 0xf5}, {0x04, 0x05}, {0xef, 0x06}, + {0x07, 0xe9}, {0xe1, 0x08}, {0x09, 0xe8}, {0x0a, 0x0b}, {0xe5, 0x0c}, + {0xa0, 0x0d}, }, + { {0x0d, 0x0e}, {0xa7, 0xac}, {0xf3, 0xad}, {0x01, 0x02}, {0x9b, 0xf9}, + {0xf5, 0xae}, {0x03, 0xee}, {0x04, 0xf2}, {0x05, 0x06}, {0xf4, 0x07}, + {0x08, 0x09}, {0xef, 0xe1}, {0xa0, 0x0a}, {0xe9, 0x0b}, {0x0c, 0xe5}, }, + { {0x14, 0x15}, {0xac, 0xe2}, {0xf8, 0x9b}, {0xae, 0xfa}, {0x01, 0xeb}, + {0x02, 0xa0}, {0x03, 0x04}, {0xf0, 0x05}, {0x06, 0xe6}, {0xf6, 0x07}, + {0xe4, 0xed}, {0xe7, 0x08}, {0xe1, 0xef}, {0xf2, 0x09}, {0x0a, 0x0b}, + {0xec, 0x0c}, {0xe5, 0xe3}, {0x0d, 0xf4}, {0x0e, 0xf3}, {0x0f, 0x10}, + {0x11, 0xee}, {0x12, 0x13}, }, + { {0x03, 0xef}, {0x9b, 0xe1}, {0xe5, 0xf5}, {0x01, 0x02}, }, + { {0x08, 0x09}, {0xec, 0xf9}, {0xa7, 0xee}, {0x01, 0xac}, {0x9b, 0xae}, + {0x02, 0x03}, {0x04, 0xf3}, {0x05, 0xe9}, {0x06, 0xa0}, {0x07, 0xe5}, }, + { {0x16, 0x17}, {0xa7, 0xad}, {0xee, 0xe3}, {0xeb, 0xf2}, {0x9b, 0xe2}, + {0x01, 0x02}, {0xf5, 0x03}, {0xf4, 0xac}, {0x04, 0x05}, {0xe6, 0xed}, + {0xf6, 0x06}, {0xae, 0xf0}, {0x07, 0x08}, {0xf3, 0x09}, {0x0a, 0xe4}, + {0x0b, 0x0c}, {0xf9, 0x0d}, {0xef, 0x0e}, {0xe1, 0x0f}, {0x10, 0xe9}, + {0xec, 0x11}, {0xa0, 0xe5}, {0x12, 0x13}, {0x14, 0x15}, }, + { {0x0c, 0x0d}, {0xa7, 0xbb}, {0x9b, 0x01}, {0xf9, 0xae}, {0xe2, 0x02}, + {0xed, 0xf3}, {0x03, 0xf5}, {0xef, 0xf0}, {0x04, 0x05}, {0xe9, 0x06}, + {0x07, 0x08}, {0x09, 0xa0}, {0xe1, 0xe5}, {0x0a, 0x0b}, }, + { {0x19, 0x1a}, {0xad, 0xbb}, {0xe2, 0xea}, {0xed, 0xf2}, {0xfa, 0xe6}, + {0xec, 0x01}, {0x02, 0x03}, {0x9b, 0xf5}, {0x04, 0xa7}, {0xf6, 0xf9}, + {0x05, 0x06}, {0xeb, 0xef}, {0x07, 0x08}, {0x09, 0x0a}, {0xac, 0x0b}, + {0x0c, 0xe3}, {0xae, 0x0d}, {0xee, 0xe9}, {0x0e, 0xe1}, {0x0f, 0xf3}, + {0x10, 0x11}, {0xf4, 0x12}, {0xe7, 0xe5}, {0x13, 0x14}, {0xe4, 0x15}, + {0x16, 0x17}, {0xa0, 0x18}, }, + { {0x1a, 0x1b}, {0xc2, 0x9b}, {0xad, 0xac}, {0xf8, 0x01}, {0xae, 0x02}, + {0x03, 0xe5}, {0xe7, 0xe8}, {0xf9, 0xe9}, {0xeb, 0x04}, {0xe3, 0xe1}, + {0x05, 0xf6}, {0x06, 0xe4}, {0x07, 0xe2}, {0xf0, 0x08}, {0x09, 0xf3}, + {0xf4, 0xf7}, {0xef, 0x0a}, {0x0b, 0x0c}, {0x0d, 0xec}, {0x0e, 0x0f}, + {0x10, 0xf5}, {0xed, 0x11}, {0xe6, 0xa0}, {0x12, 0xf2}, {0x13, 0x14}, + {0x15, 0xee}, {0x16, 0x17}, {0x18, 0x19}, }, + { {0x0e, 0x0f}, {0xad, 0xed}, {0xf9, 0x9b}, {0xae, 0x01}, {0xf3, 0x02}, + {0x03, 0xf5}, {0xf4, 0xf0}, {0x04, 0xef}, {0x05, 0xe9}, {0x06, 0xe8}, + {0xa0, 0xe1}, {0xec, 0x07}, {0xf2, 0x08}, {0xe5, 0x09}, {0x0a, 0x0b}, + {0x0c, 0x0d}, }, + { {0x9b, 0xf5}, }, + { {0x19, 0x1a}, {0xa9, 0xbb}, {0xf6, 0xe6}, {0x01, 0x9b}, {0xad, 0xe2}, + {0xf0, 0x02}, {0xa7, 0x03}, {0x04, 0x05}, {0xf5, 0xe3}, {0xac, 0xe7}, + {0xf2, 0x06}, {0xeb, 0x07}, {0xec, 0xed}, {0xee, 0xf9}, {0x08, 0xae}, + {0x09, 0x0a}, {0xe4, 0x0b}, {0x0c, 0xf4}, {0x0d, 0xf3}, {0x0e, 0x0f}, + {0x10, 0xe1}, {0xef, 0x11}, {0xe9, 0x12}, {0x13, 0xe5}, {0x14, 0xa0}, + {0x15, 0x16}, {0x17, 0x18}, }, + { {0xa0, 0x16}, {0xa2, 0xa7}, {0xe2, 0xeb}, {0xed, 0xee}, {0x9b, 0xf7}, + {0x01, 0x02}, {0x03, 0xbb}, {0xf9, 0xf0}, {0x04, 0x05}, {0xec, 0x06}, + {0x07, 0x08}, {0xf5, 0xe1}, {0x09, 0xac}, {0xe3, 0x0a}, {0xe8, 0x0b}, + {0xe9, 0x0c}, {0xef, 0xf3}, {0xae, 0x0d}, {0x0e, 0xe5}, {0x0f, 0x10}, + {0x11, 0xf4}, {0x12, 0x13}, {0x14, 0x15}, }, + { {0x14, 0x15}, {0xbb, 0xe2}, {0xad, 0xed}, {0x01, 0x9b}, {0xa7, 0xe3}, + {0xac, 0xec}, {0xee, 0x02}, {0xf7, 0x03}, {0x04, 0xf9}, {0x05, 0x06}, + {0x07, 0x08}, {0xf4, 0xae}, {0xf5, 0x09}, {0x0a, 0xf2}, {0xe1, 0xf3}, + {0x0b, 0x0c}, {0x0d, 0xe9}, {0x0e, 0x0f}, {0xef, 0xe5}, {0x10, 0xa0}, + {0xe8, 0x11}, {0x12, 0x13}, }, + { {0x11, 0x12}, {0xef, 0xf6}, {0x9b, 0xeb}, {0xf9, 0x01}, {0xa0, 0xe2}, + {0x02, 0xe1}, {0x03, 0xed}, {0x04, 0xe3}, {0xe9, 0x05}, {0xe4, 0xe5}, + {0xe7, 0x06}, {0xec, 0xf0}, {0x07, 0x08}, {0x09, 0x0a}, {0x0b, 0xf3}, + {0x0c, 0xf4}, {0xee, 0x0d}, {0xf2, 0x0e}, {0x0f, 0x10}, }, + { {0x05, 0xe5}, {0xf3, 0xf9}, {0x9b, 0x01}, {0xef, 0x02}, {0x03, 0xe1}, + {0x04, 0xe9}, }, + { {0x0a, 0x0b}, {0xae, 0x9b}, {0xec, 0xed}, {0x01, 0x02}, {0xf3, 0xee}, + {0xf2, 0x03}, {0xe5, 0x04}, {0xe8, 0xa0}, {0xe1, 0x05}, {0xef, 0x06}, + {0x07, 0x08}, {0xe9, 0x09}, }, + { {0x05, 0x06}, {0xa0, 0xac}, {0xad, 0xf4}, {0xe9, 0x01}, {0x02, 0xe1}, + {0xe5, 0x03}, {0x9b, 0x04}, }, + { {0x11, 0xa0}, {0xbf, 0xe1}, {0xe2, 0xe6}, {0xed, 0xe4}, {0xe9, 0xf7}, + {0xa7, 0x01}, {0x02, 0xbb}, {0x03, 0x04}, {0xec, 0x05}, {0x9b, 0xee}, + {0x06, 0xef}, {0x07, 0xac}, {0xe5, 0xf3}, {0x08, 0x09}, {0x0a, 0xae}, + {0x0b, 0x0c}, {0x0d, 0x0e}, {0x0f, 0x10}, }, + { {0x06, 0x07}, {0xa0, 0xae}, {0xe1, 0xe5}, {0xec, 0xfa}, {0x9b, 0xef}, + {0xe9, 0x01}, {0x02, 0x03}, {0x04, 0x05}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, +}; + +static struct hufftree_entry program_title_hufftree[][128] = { + { {0x1b, 0x1c}, {0xb4, 0xa4}, {0xb2, 0xb7}, {0xda, 0x01}, {0xd1, 0x02}, + {0x03, 0x9b}, {0x04, 0xd5}, {0xd9, 0x05}, {0xcb, 0xd6}, {0x06, 0xcf}, + {0x07, 0x08}, {0xca, 0x09}, {0xc9, 0xc5}, {0xc6, 0x0a}, {0xd2, 0xc4}, + {0xc7, 0xcc}, {0xd0, 0xc8}, {0xd7, 0xce}, {0x0b, 0xc1}, {0x0c, 0xc2}, + {0xcd, 0xc3}, {0x0d, 0x0e}, {0x0f, 0x10}, {0xd3, 0x11}, {0xd4, 0x12}, + {0x13, 0x14}, {0x15, 0x16}, {0x17, 0x18}, {0x19, 0x1a}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x29, 0x2a}, {0xd8, 0xe5}, {0xb9, 0x01}, {0xa7, 0xb1}, {0xec, 0xd1}, + {0x02, 0xad}, {0xb2, 0xda}, {0xe3, 0xb3}, {0x03, 0xe4}, {0xe6, 0x04}, + {0x9b, 0xe2}, {0x05, 0x06}, {0x07, 0x08}, {0x09, 0xd5}, {0x0a, 0xd6}, + {0x0b, 0xd9}, {0x0c, 0xa6}, {0xe9, 0xcb}, {0xc5, 0xcf}, {0x0d, 0x0e}, + {0xca, 0xc9}, {0x0f, 0xc7}, {0x10, 0x11}, {0xe1, 0x12}, {0x13, 0xc6}, + {0xd2, 0xc8}, {0xce, 0xc1}, {0xc4, 0xd0}, {0xcc, 0x14}, {0x15, 0xef}, + {0xc2, 0xd7}, {0x16, 0xcd}, {0x17, 0xf4}, {0xd4, 0x18}, {0x19, 0x1a}, + {0xc3, 0xd3}, {0x1b, 0x1c}, {0x1d, 0x1e}, {0x1f, 0x20}, {0x21, 0x22}, + {0x23, 0x24}, {0x25, 0x26}, {0x27, 0x28}, }, + { {0x01, 0x80}, {0xa0, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0xb1, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0xa0}, }, + { {0x04, 0xf3}, {0xe4, 0xb9}, {0x01, 0xf4}, {0xa0, 0x9b}, {0x02, 0x03}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x01, 0x02}, {0x9b, 0xc1}, {0xc8, 0xd3}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0xa0}, }, + { {0x07, 0x08}, {0xb1, 0xd2}, {0xd3, 0xd4}, {0xd5, 0xad}, {0xcd, 0xc1}, + {0x01, 0x02}, {0x03, 0xa0}, {0x04, 0x9b}, {0x05, 0x06}, }, + { {0xa0, 0x05}, {0xc9, 0xd7}, {0xd3, 0x01}, {0x02, 0x9b}, {0xae, 0x80}, + {0x03, 0x04}, }, + { {0x9b, 0x9b}, }, + { {0x02, 0x03}, {0xad, 0x9b}, {0x01, 0x80}, {0xa0, 0xb0}, }, + { {0x04, 0x05}, {0x80, 0x9b}, {0xb1, 0xb2}, {0xa0, 0xb0}, {0xb9, 0x01}, + {0x02, 0x03}, }, + { {0x02, 0x03}, {0xb1, 0xba}, {0x01, 0xb0}, {0x9b, 0x80}, }, + { {0x80, 0x01}, {0xb0, 0x9b}, }, + { {0x9b, 0xb8}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0xb0}, }, + { {0x9b, 0xa0}, }, + { {0x02, 0x03}, {0xb1, 0xb3}, {0xb9, 0xb0}, {0x01, 0x9b}, }, + { {0x9b, 0xa0}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x80}, }, + { {0x9b, 0x9b}, }, + { {0x13, 0x14}, {0xaa, 0xad}, {0xae, 0xf6}, {0xe7, 0xf4}, {0xe2, 0xe9}, + {0x01, 0x02}, {0xc2, 0xf0}, {0x9b, 0xf3}, {0xe3, 0xe6}, {0xf7, 0x03}, + {0xf5, 0x04}, {0x05, 0x06}, {0xf2, 0x07}, {0x08, 0x09}, {0x0a, 0x0b}, + {0x0c, 0xe4}, {0xa0, 0x0d}, {0xec, 0xee}, {0x0e, 0xed}, {0x0f, 0x10}, + {0x11, 0x12}, }, + { {0x08, 0x09}, {0xc1, 0xd3}, {0x9b, 0x01}, {0xc3, 0x02}, {0xe9, 0xec}, + {0x03, 0xf2}, {0xf5, 0x04}, {0xef, 0xe1}, {0x05, 0xe5}, {0x06, 0x07}, }, + { {0x0b, 0x0c}, {0xc1, 0xf9}, {0x01, 0xc2}, {0xcf, 0xe5}, {0xf5, 0x9b}, + {0xe9, 0x02}, {0xa0, 0x03}, {0x04, 0x05}, {0xf2, 0x06}, {0xec, 0x07}, + {0xe1, 0x08}, {0x09, 0xe8}, {0x0a, 0xef}, }, + { {0x05, 0x06}, {0xf9, 0x9b}, {0x01, 0xf5}, {0x02, 0xf2}, {0xe9, 0xe5}, + {0xef, 0x03}, {0xe1, 0x04}, }, + { {0x0a, 0x0b}, {0xf1, 0xf5}, {0xf3, 0x01}, {0xed, 0xf9}, {0xc3, 0x02}, + {0xec, 0xee}, {0xe4, 0xf8}, {0x03, 0x9b}, {0xf6, 0x04}, {0x05, 0xe1}, + {0x06, 0x07}, {0x08, 0x09}, }, + { {0x07, 0x08}, {0xa0, 0x9b}, {0xcc, 0x01}, {0xe5, 0x02}, {0xec, 0xf5}, + {0xef, 0x03}, {0xe9, 0xf2}, {0x04, 0x05}, {0xe1, 0x06}, }, + { {0x09, 0x0a}, {0xae, 0xec}, {0xf9, 0xc1}, {0xe8, 0x01}, {0x9b, 0x02}, + {0x03, 0x04}, {0xe1, 0xf5}, {0xe9, 0x05}, {0xe5, 0x06}, {0xf2, 0xef}, + {0x07, 0x08}, }, + { {0xef, 0x05}, {0x80, 0x9b}, {0xf5, 0x01}, {0x02, 0xe9}, {0xe1, 0x03}, + {0xe5, 0x04}, }, + { {0xee, 0x0b}, {0xba, 0xd4}, {0xae, 0xf2}, {0xe3, 0x01}, {0xa0, 0x02}, + {0x80, 0x9b}, {0xed, 0x03}, {0xc9, 0xf3}, {0xf4, 0x04}, {0x05, 0x06}, + {0x07, 0x08}, {0x09, 0x0a}, }, + { {0x02, 0x03}, {0x9b, 0xf5}, {0x01, 0xe1}, {0xef, 0xe5}, }, + { {0x05, 0xe9}, {0xe1, 0xef}, {0xf5, 0xee}, {0x9b, 0xe5}, {0x01, 0x02}, + {0x03, 0x04}, }, + { {0x04, 0x05}, {0xa0, 0x9b}, {0x01, 0xf5}, {0x02, 0xe5}, {0xef, 0x03}, + {0xe1, 0xe9}, }, + { {0x08, 0x09}, {0xaa, 0xd4}, {0x01, 0x9b}, {0xe3, 0x02}, {0xf2, 0x03}, + {0xe5, 0x04}, {0xf5, 0xf9}, {0xe9, 0x05}, {0xef, 0x06}, {0x07, 0xe1}, }, + { {0xe5, 0x08}, {0xce, 0xa0}, {0xc6, 0xf5}, {0x01, 0x02}, {0x9b, 0xc2}, + {0x03, 0xe1}, {0x04, 0xef}, {0x05, 0xe9}, {0x06, 0x07}, }, + { {0x09, 0x0a}, {0xe4, 0xf3}, {0xe6, 0xf6}, {0xf7, 0xf0}, {0xf2, 0x01}, + {0xec, 0x02}, {0x03, 0xa0}, {0x9b, 0x04}, {0x05, 0xf5}, {0x06, 0x07}, + {0xee, 0x08}, }, + { {0x0b, 0x0c}, {0xa0, 0xf3}, {0xf9, 0xae}, {0xd2, 0xc7}, {0x01, 0x9b}, + {0x02, 0xf5}, {0x03, 0x04}, {0x05, 0xe9}, {0xec, 0x06}, {0xe5, 0x07}, + {0xef, 0x08}, {0xe1, 0x09}, {0xf2, 0x0a}, }, + { {0x01, 0xf5}, {0x9b, 0xd6}, }, + { {0x04, 0x05}, {0xe8, 0x9b}, {0x01, 0xf5}, {0x02, 0xe1}, {0xe9, 0xef}, + {0x03, 0xe5}, }, + { {0x10, 0x11}, {0xaa, 0xec}, {0xf1, 0xae}, {0xa0, 0xf7}, {0xed, 0xee}, + {0x01, 0x02}, {0x9b, 0xeb}, {0x03, 0x04}, {0x05, 0x06}, {0xe3, 0x07}, + {0xef, 0x08}, {0xe9, 0xf5}, {0x09, 0xe1}, {0xe5, 0xf0}, {0xe8, 0x0a}, + {0x0b, 0x0c}, {0x0d, 0xf4}, {0x0e, 0x0f}, }, + { {0xe8, 0x0a}, {0xad, 0xce}, {0x9b, 0x01}, {0xd6, 0x02}, {0xf5, 0xf7}, + {0x03, 0x04}, {0xe1, 0xe5}, {0xe9, 0x05}, {0xf2, 0x06}, {0xef, 0x07}, + {0x08, 0x09}, }, + { {0xee, 0x03}, {0xec, 0xae}, {0x01, 0x9b}, {0x02, 0xf0}, }, + { {0x06, 0xe9}, {0xa0, 0xc3}, {0xef, 0x9b}, {0xe5, 0x01}, {0x80, 0x02}, + {0x03, 0xe1}, {0x04, 0x05}, }, + { {0x06, 0x07}, {0xc6, 0xd7}, {0x01, 0x9b}, {0xf2, 0x02}, {0x03, 0xe8}, + {0xe5, 0xe1}, {0x04, 0xe9}, {0xef, 0x05}, }, + { {0x9b, 0x9b}, }, + { {0x02, 0xef}, {0xe1, 0x9b}, {0x01, 0xe5}, }, + { {0x01, 0xef}, {0x9b, 0xe1}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x19, 0x1a}, {0x9b, 0xba}, {0xe5, 0xea}, {0xf8, 0x01}, {0x02, 0xe6}, + {0xa7, 0x03}, {0xfa, 0xe8}, {0x04, 0xf7}, {0x05, 0xf5}, {0xe2, 0x06}, + {0xeb, 0x07}, {0xf0, 0x08}, {0x80, 0xf6}, {0xe7, 0x09}, {0xe4, 0x0a}, + {0xa0, 0xe9}, {0x0b, 0xe3}, {0xf9, 0x0c}, {0x0d, 0xed}, {0x0e, 0x0f}, + {0xf3, 0x10}, {0x11, 0xec}, {0x12, 0xf4}, {0xf2, 0x13}, {0xee, 0x14}, + {0x15, 0x16}, {0x17, 0x18}, }, + { {0x0a, 0x0b}, {0xf3, 0x9b}, {0xf5, 0xe2}, {0x01, 0x80}, {0xa0, 0x02}, + {0xe5, 0xf2}, {0xe9, 0x03}, {0xec, 0x04}, {0xf9, 0x05}, {0xef, 0x06}, + {0xe1, 0x07}, {0x08, 0x09}, }, + { {0x10, 0x11}, {0xc3, 0xcc}, {0xc7, 0x9b}, {0xe3, 0x01}, {0x80, 0xec}, + {0xf9, 0x02}, {0xf3, 0x03}, {0xf5, 0x04}, {0x05, 0xf2}, {0x06, 0xe9}, + {0xa0, 0x07}, {0x08, 0xef}, {0xf4, 0x09}, {0x0a, 0xe1}, {0x0b, 0xe8}, + {0xeb, 0xe5}, {0x0c, 0x0d}, {0x0e, 0x0f}, }, + { {0x0e, 0x0f}, {0xae, 0xf5}, {0xf7, 0x01}, {0xec, 0x02}, {0xe4, 0xe7}, + {0xf2, 0x03}, {0x9b, 0xef}, {0x04, 0xf6}, {0x05, 0x06}, {0xf9, 0xf3}, + {0x07, 0xe9}, {0xe1, 0x08}, {0x09, 0x80}, {0x0a, 0x0b}, {0xe5, 0x0c}, + {0x0d, 0xa0}, }, + { {0x1e, 0x1f}, {0x9b, 0xa1}, {0xad, 0xe8}, {0xea, 0xf1}, {0xf5, 0xfa}, + {0x01, 0x02}, {0x03, 0x04}, {0xba, 0xf8}, {0xa7, 0xe2}, {0xe9, 0x05}, + {0x06, 0x07}, {0xe6, 0xed}, {0xe7, 0xeb}, {0x08, 0x09}, {0xf6, 0xf0}, + {0x0a, 0xef}, {0x0b, 0xe3}, {0x0c, 0x0d}, {0x0e, 0xf9}, {0x0f, 0xe4}, + {0xec, 0x10}, {0xe5, 0x11}, {0xf4, 0xf7}, {0x12, 0x13}, {0xe1, 0x14}, + {0x15, 0x16}, {0xee, 0xf3}, {0x17, 0x80}, {0x18, 0x19}, {0xf2, 0x1a}, + {0x1b, 0xa0}, {0x1c, 0x1d}, }, + { {0xa0, 0x0b}, {0xf5, 0x9b}, {0x01, 0xec}, {0xf3, 0xf2}, {0x80, 0xe1}, + {0x02, 0x03}, {0xf4, 0xe9}, {0xef, 0xe6}, {0x04, 0x05}, {0x06, 0x07}, + {0xe5, 0x08}, {0x09, 0x0a}, }, + { {0x0f, 0x10}, {0xba, 0xf9}, {0xa7, 0xf4}, {0x9b, 0x01}, {0xe7, 0xec}, + {0x02, 0xee}, {0x03, 0xef}, {0xf5, 0x04}, {0xf2, 0x05}, {0x06, 0xe9}, + {0x07, 0xf3}, {0xe1, 0x08}, {0x09, 0x0a}, {0x0b, 0xe5}, {0x80, 0x0c}, + {0xe8, 0xa0}, {0x0d, 0x0e}, }, + { {0xe5, 0x0d}, {0xe2, 0xf5}, {0xf7, 0x9b}, {0xec, 0x01}, {0xf9, 0xee}, + {0x02, 0x03}, {0x04, 0xf2}, {0x05, 0x80}, {0x06, 0xa0}, {0xe1, 0xef}, + {0x07, 0xf4}, {0xe9, 0x08}, {0x09, 0x0a}, {0x0b, 0x0c}, }, + { {0x15, 0x16}, {0xa1, 0xf8}, {0xe9, 0xeb}, {0x01, 0x80}, {0x9b, 0xfa}, + {0xe2, 0x02}, {0x03, 0x04}, {0xa0, 0xf0}, {0x05, 0x06}, {0x07, 0xe1}, + {0x08, 0xe6}, {0xf2, 0xed}, {0xf6, 0x09}, {0xe4, 0x0a}, {0xef, 0xf4}, + {0xec, 0xf3}, {0xe7, 0xe5}, {0x0b, 0xe3}, {0x0c, 0x0d}, {0x0e, 0x0f}, + {0x10, 0x11}, {0x12, 0x13}, {0xee, 0x14}, }, + { {0xef, 0x01}, {0x9b, 0xe1}, }, + { {0x0b, 0x0c}, {0xd4, 0xef}, {0xe6, 0xec}, {0xf7, 0xe1}, {0x01, 0xba}, + {0x02, 0x9b}, {0xf9, 0x03}, {0x04, 0x05}, {0xf3, 0x06}, {0x07, 0x08}, + {0xe9, 0xa0}, {0x09, 0x80}, {0xe5, 0x0a}, }, + { {0x15, 0x16}, {0xa7, 0xba}, {0xe3, 0xf7}, {0xf2, 0xad}, {0xe2, 0x01}, + {0x02, 0x9b}, {0xe6, 0x03}, {0xed, 0xf6}, {0x04, 0xeb}, {0x05, 0xf4}, + {0x06, 0x07}, {0x08, 0xf3}, {0x09, 0xf5}, {0x0a, 0xef}, {0x0b, 0x0c}, + {0x80, 0xf9}, {0xe1, 0x0d}, {0xe4, 0xe9}, {0xa0, 0x0e}, {0x0f, 0xec}, + {0xe5, 0x10}, {0x11, 0x12}, {0x13, 0x14}, }, + { {0x0a, 0x0b}, {0xf9, 0x9b}, {0xf5, 0xf3}, {0x01, 0x02}, {0xe2, 0xed}, + {0x80, 0x03}, {0xf0, 0xef}, {0x04, 0xa0}, {0x05, 0xe9}, {0x06, 0xe1}, + {0x07, 0x08}, {0x09, 0xe5}, }, + { {0x18, 0x19}, {0xe2, 0xea}, {0xf2, 0xe8}, {0xec, 0xed}, {0xfa, 0x9b}, + {0x01, 0xf5}, {0x02, 0x03}, {0xf6, 0x04}, {0xba, 0xe6}, {0x05, 0x06}, + {0xeb, 0xef}, {0x07, 0xa7}, {0xf9, 0x08}, {0x09, 0x0a}, {0x0b, 0xe3}, + {0x0c, 0xee}, {0xe1, 0x0d}, {0xf3, 0x0e}, {0xe9, 0x0f}, {0x10, 0xf4}, + {0x80, 0xe4}, {0xe5, 0x11}, {0x12, 0xe7}, {0xa0, 0x13}, {0x14, 0x15}, + {0x16, 0x17}, }, + { {0x1b, 0x1c}, {0xae, 0xfa}, {0xbf, 0x01}, {0xa7, 0x9b}, {0x02, 0xe9}, + {0xf8, 0xf9}, {0x03, 0xe5}, {0xe8, 0x04}, {0xe1, 0xeb}, {0x05, 0xe2}, + {0x06, 0x07}, {0xe3, 0x08}, {0xe7, 0xf4}, {0x09, 0x80}, {0xf6, 0xf0}, + {0x0a, 0xe4}, {0x0b, 0xf3}, {0xf7, 0x0c}, {0x0d, 0xef}, {0xec, 0xa0}, + {0x0e, 0x0f}, {0xed, 0xe6}, {0x10, 0xf5}, {0x11, 0x12}, {0x13, 0x14}, + {0x15, 0xf2}, {0x16, 0xee}, {0x17, 0x18}, {0x19, 0x1a}, }, + { {0x0e, 0x0f}, {0xed, 0xa7}, {0x9b, 0xe4}, {0x01, 0xf9}, {0xf3, 0xf2}, + {0xf4, 0x02}, {0xe8, 0x03}, {0xec, 0xf0}, {0x04, 0xe1}, {0xe9, 0x05}, + {0x06, 0x80}, {0xa0, 0x07}, {0x08, 0x09}, {0x0a, 0xe5}, {0xef, 0x0b}, + {0x0c, 0x0d}, }, + { {0x9b, 0xf5}, }, + { {0x18, 0x19}, {0xba, 0xac}, {0xf6, 0x9b}, {0xf0, 0xe2}, {0x01, 0xe6}, + {0x02, 0xa7}, {0xae, 0xe7}, {0x03, 0xe3}, {0xf5, 0x04}, {0xed, 0x05}, + {0x06, 0x07}, {0xeb, 0x08}, {0x09, 0xee}, {0xf2, 0x0a}, {0xe4, 0x0b}, + {0xf9, 0xec}, {0x0c, 0x0d}, {0xf4, 0x80}, {0x0e, 0xef}, {0xf3, 0xa0}, + {0xe1, 0x0f}, {0xe9, 0x10}, {0x11, 0xe5}, {0x12, 0x13}, {0x14, 0x15}, + {0x16, 0x17}, }, + { {0x19, 0x1a}, {0xa7, 0xac}, {0xbf, 0xc3}, {0xc8, 0xe4}, {0xe6, 0xed}, + {0xf2, 0xae}, {0xec, 0xee}, {0xf9, 0x01}, {0x02, 0x03}, {0x04, 0xba}, + {0x05, 0x9b}, {0xf5, 0x06}, {0x07, 0x08}, {0x09, 0xeb}, {0xf0, 0x0a}, + {0x0b, 0x0c}, {0xe1, 0xe3}, {0x0d, 0xe8}, {0x0e, 0x0f}, {0xef, 0x10}, + {0x11, 0xf3}, {0x12, 0xe9}, {0x13, 0xe5}, {0x14, 0x15}, {0xf4, 0x16}, + {0x17, 0xa0}, {0x18, 0x80}, }, + { {0x14, 0x15}, {0xba, 0xbf}, {0xe4, 0xf7}, {0x9b, 0xa7}, {0x01, 0xee}, + {0x02, 0x03}, {0x04, 0xe3}, {0xe2, 0xed}, {0x05, 0xf9}, {0x06, 0xf4}, + {0x07, 0xec}, {0x08, 0xf5}, {0xf2, 0x09}, {0xe1, 0xf3}, {0x0a, 0xef}, + {0x0b, 0x0c}, {0x0d, 0xe9}, {0x80, 0xe5}, {0x0e, 0xa0}, {0x0f, 0xe8}, + {0x10, 0x11}, {0x12, 0x13}, }, + { {0x11, 0x12}, {0xeb, 0xfa}, {0x80, 0xe6}, {0x9b, 0x01}, {0xa0, 0x02}, + {0x03, 0xe9}, {0xe1, 0x04}, {0xe4, 0xf0}, {0xed, 0xe2}, {0xe3, 0xe7}, + {0xec, 0x05}, {0xe5, 0x06}, {0x07, 0x08}, {0x09, 0xf4}, {0x0a, 0x0b}, + {0x0c, 0xf3}, {0xee, 0x0d}, {0x0e, 0xf2}, {0x0f, 0x10}, }, + { {0x04, 0xe5}, {0xf3, 0xef}, {0x9b, 0x01}, {0xe1, 0x02}, {0x03, 0xe9}, }, + { {0x0b, 0x0c}, {0xa7, 0xe2}, {0xec, 0xe3}, {0xf2, 0x01}, {0x9b, 0x02}, + {0x03, 0x04}, {0xe9, 0xef}, {0xee, 0xe5}, {0xe1, 0x80}, {0x05, 0xa0}, + {0x06, 0x07}, {0x08, 0x09}, {0xf3, 0x0a}, }, + { {0x05, 0x06}, {0x9b, 0xa0}, {0xe1, 0xe5}, {0xe9, 0x01}, {0x80, 0xf0}, + {0x02, 0xf4}, {0x03, 0x04}, }, + { {0xa0, 0x13}, {0xe3, 0xad}, {0xe4, 0xe9}, {0xee, 0xef}, {0xf0, 0xf4}, + {0xf6, 0xa1}, {0xe1, 0xed}, {0x01, 0xe2}, {0x02, 0x03}, {0x04, 0xa7}, + {0x05, 0x06}, {0xf7, 0x07}, {0x9b, 0xec}, {0x08, 0xe5}, {0x09, 0x0a}, + {0x0b, 0x0c}, {0x0d, 0x0e}, {0xf3, 0x0f}, {0x10, 0x11}, {0x80, 0x12}, }, + { {0x05, 0x06}, {0xe5, 0xfa}, {0xa0, 0xf9}, {0x9b, 0x01}, {0x80, 0xe9}, + {0x02, 0xe1}, {0x03, 0x04}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, + { {0x9b, 0x9b}, }, +}; + + + +static inline void huffbuff_init(struct huffbuff *hbuf, uint8_t *buf, uint32_t buf_len) +{ + memset(hbuf, 0, sizeof(struct huffbuff)); + hbuf->buf = buf; + hbuf->buf_len = buf_len; +} + +static inline int huffbuff_bits(struct huffbuff *hbuf, uint8_t nbits) +{ + uint8_t result = 0; + + if (nbits > 8) + return -1; + + while(nbits--) { + if (hbuf->cur_byte >= hbuf->buf_len) { + return -1; + } + + result <<= 1; + if (hbuf->buf[hbuf->cur_byte] & (0x80 >> hbuf->cur_bit)) + result |= 1; + + if (++hbuf->cur_bit > 7) { + hbuf->cur_byte++; + hbuf->cur_bit = 0; + } + } + + return result; +} + +static inline int append_unicode_char(uint8_t **destbuf, size_t *destbuflen, size_t *destbufpos, + uint32_t c) +{ + uint8_t tmp[3]; + int tmplen = 0; + + // encode the unicode character first of all + if (c < 0x80) { + tmp[0] = c; + tmplen = 1; + } else if (c < 0x800) { + tmp[0] = 0xc0 | ((c >> 6) & 0x1f); + tmp[1] = 0x80 | (c & 0x3f); + tmplen = 2; + } else if (c < 0x10000) { + tmp[0] = 0xe0 | ((c >> 12) & 0x0f); + tmp[1] = 0x80 | ((c >> 6) & 0x3f); + tmp[2] = 0x80 | (c & 0x3f); + tmplen = 3; + } else { + return -1; + } + + // do we have enough buffer space? + if ((*destbufpos + tmplen) >= *destbuflen) { + uint8_t *new_dest = realloc(*destbuf, *destbuflen + DEST_ALLOC_DELTA); + if (new_dest == NULL) + return -ENOMEM; + *destbuf = new_dest; + *destbuflen += DEST_ALLOC_DELTA; + } + + // copy it into position + memcpy(*destbuf + *destbufpos, tmp, tmplen); + *destbufpos += tmplen; + + return 0; +} + +static inline int unicode_decode(uint8_t *srcbuf, size_t srcbuflen, int mode, + uint8_t **destbuf, size_t *destbuflen, size_t *destbufpos) +{ + size_t i; + uint32_t msb = mode << 8; + + for(i=0; i< srcbuflen; i++) { + if (append_unicode_char(destbuf, destbuflen, destbufpos, msb + srcbuf[i])) + return -1; + } + + return *destbufpos; +} + +static int huffman_decode_uncompressed(struct huffbuff *hbuf, + uint8_t **destbuf, size_t *destbuflen, size_t *destbufpos) +{ + int c; + + while(hbuf->cur_byte < hbuf->buf_len) { + // get next byte + if ((c = huffbuff_bits(hbuf, 8)) < 0) + return -1; + + switch(c) { + case HUFFSTRING_END: + return 0; + + case HUFFSTRING_ESCAPE: + return HUFFSTRING_ESCAPE; + + default: + if (append_unicode_char(destbuf, destbuflen, destbufpos, c)) + return -1; + + // if it is 7 bit, we swap back to the compressed context + if ((c & 0x80) == 0) + return c; + + // characters following an 8 bit uncompressed char are uncompressed as well + break; + } + } + + // ran out of string; pretend we saw an end of string char + return HUFFSTRING_END; +} + +static int huffman_decode(uint8_t *src, size_t srclen, + uint8_t **destbuf, size_t *destbuflen, size_t *destbufpos, + struct hufftree_entry hufftree[][128]) +{ + struct huffbuff hbuf; + int bit; + struct hufftree_entry *tree = hufftree[0]; + uint8_t treeidx = 0; + uint8_t treeval; + int tmp; + + huffbuff_init(&hbuf, src, srclen); + + while(hbuf.cur_byte < hbuf.buf_len) { + // get the next bit + if ((bit = huffbuff_bits(&hbuf, 1)) < 0) + return *destbufpos; + + if (!bit) { + treeval = tree[treeidx].left_idx; + } else { + treeval = tree[treeidx].right_idx; + } + + if (treeval & HUFFTREE_LITERAL_MASK) { + switch(treeval & ~HUFFTREE_LITERAL_MASK) { + case HUFFSTRING_END: + return 0; + + case HUFFSTRING_ESCAPE: + if ((tmp = + huffman_decode_uncompressed(&hbuf, + destbuf, destbuflen, destbufpos)) < 0) + return tmp; + if (tmp == 0) + return *destbufpos; + + tree = hufftree[tmp]; + treeidx = 0; + break; + + default: + // stash it + if (append_unicode_char(destbuf, destbuflen, destbufpos, + treeval & ~HUFFTREE_LITERAL_MASK)) + return -1; + tree = hufftree[treeval & ~HUFFTREE_LITERAL_MASK]; + treeidx = 0; + break; + } + } else { + treeidx = treeval; + } + } + + return *destbufpos; +} + +int atsc_text_segment_decode(struct atsc_text_string_segment *segment, + uint8_t **destbuf, size_t *destbufsize, size_t *destbufpos) +{ + if (segment->mode > ATSC_TEXT_SEGMENT_MODE_UNICODE_RANGE_MAX) + return -1; + + // mode==0 MUST be used for compressed text + if ((segment->mode) && (segment->compression_type)) + return -1; + + uint8_t *buf = atsc_text_string_segment_bytes(segment); + + switch(segment->compression_type) { + case ATSC_TEXT_COMPRESS_NONE: + return unicode_decode(buf, segment->number_bytes, segment->mode, + destbuf, destbufsize, destbufpos); + + case ATSC_TEXT_COMPRESS_PROGRAM_TITLE: + return huffman_decode(buf, segment->number_bytes, + destbuf, destbufsize, destbufpos, + program_title_hufftree); + + case ATSC_TEXT_COMPRESS_PROGRAM_DESCRIPTION: + return huffman_decode(buf, segment->number_bytes, + destbuf, destbufsize, destbufpos, + program_description_hufftree); + } + + return -1; +} diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/caption_service_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/atsc/caption_service_descriptor.h new file mode 100644 index 0000000..29d1794 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/caption_service_descriptor.h @@ -0,0 +1,137 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_ATSC_CAPTION_SERVICE_DESCRIPTOR +#define _UCSI_ATSC_CAPTION_SERVICE_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> + +/** + * atsc_caption_service_descriptor structure. + */ +struct atsc_caption_service_descriptor { + struct descriptor d; + + EBIT2(uint8_t reserved : 3; , + uint8_t number_of_services : 5; ); + /* struct atsc_caption_service_entry entries[] */ +} __ucsi_packed; + +/** + * An entry in the entries field of a atsc_caption_service_descriptor. + */ +struct atsc_caption_service_entry { + iso639lang_t language_code; + EBIT3(uint8_t digital_cc : 1; , + uint8_t reserved : 1; , + uint8_t value : 6; ); + EBIT3(uint16_t easy_reader : 1; , + uint16_t wide_aspect_ratio : 1; , + uint16_t reserved1 :14; ); +} __ucsi_packed; + +/** + * Process an atsc_caption_service_descriptor. + * + * @param d Generic descriptor pointer. + * @return atsc_caption_service_descriptor pointer, or NULL on error. + */ +static inline struct atsc_caption_service_descriptor* + atsc_caption_service_descriptor_codec(struct descriptor* d) +{ + struct atsc_caption_service_descriptor *ret = + (struct atsc_caption_service_descriptor *) d; + uint8_t *buf = (uint8_t*) d + 2; + int pos = 0; + int idx; + + if (d->len < 1) + return NULL; + pos++; + + for(idx = 0; idx < ret->number_of_services; idx++) { + if (d->len < (pos + sizeof(struct atsc_caption_service_entry))) + return NULL; + + bswap16(buf+pos+4); + + pos += sizeof(struct atsc_caption_service_entry); + } + + return (struct atsc_caption_service_descriptor*) d; +} + +/** + * Iterator for entries field of a atsc_caption_service_descriptor. + * + * @param d atsc_caption_service_descriptor pointer. + * @param pos Variable holding a pointer to the current atsc_caption_service_entry. + * @param idx Field iterator integer. + */ +#define atsc_caption_service_descriptor_entries_for_each(d, pos, idx) \ + for ((pos) = atsc_caption_service_descriptor_entries_first(d), idx=0; \ + (pos); \ + (pos) = atsc_caption_service_descriptor_entries_next(d, pos, ++idx)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct atsc_caption_service_entry* + atsc_caption_service_descriptor_entries_first(struct atsc_caption_service_descriptor *d) +{ + if (d->number_of_services == 0) + return NULL; + + return (struct atsc_caption_service_entry *) + ((uint8_t*) d + sizeof(struct atsc_caption_service_descriptor)); +} + +static inline struct atsc_caption_service_entry* + atsc_caption_service_descriptor_entries_next(struct atsc_caption_service_descriptor *d, + struct atsc_caption_service_entry *pos, + int idx) +{ + if (idx >= d->number_of_services) + return NULL; + + return (struct atsc_caption_service_entry *) + ((uint8_t *) pos + sizeof(struct atsc_caption_service_entry)); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/component_name_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/atsc/component_name_descriptor.h new file mode 100644 index 0000000..3b9cab7 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/component_name_descriptor.h @@ -0,0 +1,92 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_ATSC_COMPONENT_NAME_DESCRIPTOR +#define _UCSI_ATSC_COMPONENT_NAME_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> +#include <libucsi/atsc/types.h> + +/** + * atsc_component_name_descriptor structure. + */ +struct atsc_component_name_descriptor { + struct descriptor d; + + /* struct atsc_text text[] */ +} __ucsi_packed; + +/** + * Process an atsc_component_name_descriptor. + * + * @param d Generic descriptor pointer. + * @return atsc_component_name_descriptor pointer, or NULL on error. + */ +static inline struct atsc_component_name_descriptor* + atsc_component_name_descriptor_codec(struct descriptor* d) +{ + uint8_t *txt = ((uint8_t*) d) + sizeof(struct atsc_component_name_descriptor); + + if (atsc_text_validate(txt, d->len)) + return NULL; + + return (struct atsc_component_name_descriptor*) d; +} + +/** + * Accessor for the text field of an atsc_component_name_descriptor. + * + * @param d atsc_component_name_descriptor pointer. + * @return Pointer to the atsc_text data, or NULL on error. + */ +static inline struct atsc_text* + atsc_component_name_descriptor_text(struct atsc_component_name_descriptor *d) +{ + uint8_t *txt = ((uint8_t*) d) + sizeof(struct atsc_component_name_descriptor); + + return (struct atsc_text*) txt; +} + +/** + * Accessor for the length of the text field of an atsc_component_name_descriptor_text. + * + * @param d atsc_component_name_descriptor pointer. + * @return The length in bytes. + */ +static inline int + atsc_component_name_descriptor_text_length(struct atsc_component_name_descriptor *d) +{ + return d->d.len; +} + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/content_advisory_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/atsc/content_advisory_descriptor.h new file mode 100644 index 0000000..da19813 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/content_advisory_descriptor.h @@ -0,0 +1,235 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_ATSC_CONTENT_ADVISORY_DESCRIPTOR +#define _UCSI_ATSC_CONTENT_ADVISORY_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> + +/** + * atsc_content_advisory_descriptor structure. + */ +struct atsc_content_advisory_descriptor { + struct descriptor d; + + EBIT2(uint8_t reserved : 2; , + uint8_t rating_region_count : 6; ); + /* struct atsc_content_advisory_entry entries[] */ +} __ucsi_packed; + +/** + * An entry in the entries field of a atsc_content_advisory_descriptor. + */ +struct atsc_content_advisory_entry { + uint8_t rating_region; + uint8_t rated_dimensions; + /* struct atsc_content_advisory_entry_dimension dimensions[] */ + /* struct atsc_content_advisory_entry_part2 part2 */ +} __ucsi_packed; + +/** + * An entry in the entries field of a atsc_content_advisory_descriptor. + */ +struct atsc_content_advisory_entry_dimension { + uint8_t rating_dimension_j; + EBIT2(uint8_t reserved : 4; , + uint8_t rating_value : 4; ); +} __ucsi_packed; + +/** + * Part2 of an atsc_content_advisory_entry. + */ +struct atsc_content_advisory_entry_part2 { + uint8_t rating_description_length; + /* struct atsc_text description */ +} __ucsi_packed; + +/** + * Process an atsc_content_advisory_descriptor. + * + * @param d Generic descriptor pointer. + * @return atsc_content_advisory_descriptor pointer, or NULL on error. + */ +static inline struct atsc_content_advisory_descriptor* + atsc_content_advisory_descriptor_codec(struct descriptor* d) +{ + struct atsc_content_advisory_descriptor *ret = + (struct atsc_content_advisory_descriptor *) d; + uint8_t *buf = (uint8_t*) d + 2; + int pos = 0; + int idx; + + if (d->len < 1) + return NULL; + pos++; + + for(idx = 0; idx < ret->rating_region_count; idx++) { + if (d->len < (pos + sizeof(struct atsc_content_advisory_entry))) + return NULL; + struct atsc_content_advisory_entry *entry = + (struct atsc_content_advisory_entry *) (buf + pos); + pos += sizeof(struct atsc_content_advisory_entry); + + if (d->len < (pos + (sizeof(struct atsc_content_advisory_entry_dimension) * + entry->rated_dimensions))) + return NULL; + pos += sizeof(struct atsc_content_advisory_entry_dimension) * entry->rated_dimensions; + + if (d->len < (pos + sizeof(struct atsc_content_advisory_entry_part2))) + return NULL; + struct atsc_content_advisory_entry_part2 *part2 = + (struct atsc_content_advisory_entry_part2 *) (buf + pos); + pos += sizeof(struct atsc_content_advisory_entry_part2); + + if (d->len < (pos + part2->rating_description_length)) + return NULL; + + if (atsc_text_validate(buf+pos, part2->rating_description_length)) + return NULL; + + pos += part2->rating_description_length; + } + + return (struct atsc_content_advisory_descriptor*) d; +} + +/** + * Iterator for entries field of a atsc_content_advisory_descriptor. + * + * @param d atsc_content_advisory_descriptor pointer. + * @param pos Variable holding a pointer to the current atsc_content_advisory_entry. + * @param idx Integer used to count which entry we are in. + */ +#define atsc_content_advisory_descriptor_entries_for_each(d, pos, idx) \ + for ((pos) = atsc_content_advisory_descriptor_entries_first(d), idx=0; \ + (pos); \ + (pos) = atsc_content_advisory_descriptor_entries_next(d, pos, ++idx)) + +/** + * Iterator for dimensions field of a atsc_content_advisory_entry. + * + * @param d atsc_content_advisory_entry pointer. + * @param pos Variable holding a pointer to the current atsc_content_advisory_entry_dimension. + * @param idx Integer used to count which dimension we are in. + */ +#define atsc_content_advisory_entry_dimensions_for_each(d, pos, idx) \ + for ((pos) = atsc_content_advisory_entry_dimensions_first(d), idx=0; \ + (pos); \ + (pos) = atsc_content_advisory_entry_dimensions_next(d, pos, ++idx)) + +/** + * Accessor for the part2 field of an atsc_content_advisory_entry. + * + * @param entry atsc_content_advisory_entry pointer. + * @return struct atsc_content_advisory_entry_part2 pointer. + */ +static inline struct atsc_content_advisory_entry_part2 * + atsc_content_advisory_entry_part2(struct atsc_content_advisory_entry *entry) +{ + int pos = sizeof(struct atsc_content_advisory_entry); + pos += entry->rated_dimensions * sizeof(struct atsc_content_advisory_entry_dimension); + + return (struct atsc_content_advisory_entry_part2 *) (((uint8_t*) entry) + pos); +} + + +/** + * Accessor for the description field of an atsc_content_advisory_entry_part2. + * + * @param part2 atsc_content_advisory_entry_part2 pointer. + * @return Pointer to the atsc_text data, or NULL on error. + */ +static inline struct atsc_text* + atsc_content_advisory_entry_part2_description(struct atsc_content_advisory_entry_part2 *part2) +{ + uint8_t *txt = ((uint8_t*) part2) + sizeof(struct atsc_content_advisory_entry_part2); + + return (struct atsc_text *) txt; +} + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct atsc_content_advisory_entry* + atsc_content_advisory_descriptor_entries_first(struct atsc_content_advisory_descriptor *d) +{ + if (d->rating_region_count == 0) + return NULL; + + return (struct atsc_content_advisory_entry *) + ((uint8_t*) d + sizeof(struct atsc_content_advisory_descriptor)); +} + +static inline struct atsc_content_advisory_entry* + atsc_content_advisory_descriptor_entries_next(struct atsc_content_advisory_descriptor *d, + struct atsc_content_advisory_entry *pos, + int idx) +{ + if (idx >= d->rating_region_count) + return NULL; + struct atsc_content_advisory_entry_part2 *part2 = + atsc_content_advisory_entry_part2(pos); + + return (struct atsc_content_advisory_entry *) + ((uint8_t *) part2 + + sizeof(struct atsc_content_advisory_entry_part2) + + part2->rating_description_length); +} + +static inline struct atsc_content_advisory_entry_dimension* + atsc_content_advisory_entry_dimensions_first(struct atsc_content_advisory_entry *e) +{ + if (e->rated_dimensions == 0) + return NULL; + + return (struct atsc_content_advisory_entry_dimension *) + ((uint8_t*) e + sizeof(struct atsc_content_advisory_entry)); +} + +static inline struct atsc_content_advisory_entry_dimension* + atsc_content_advisory_entry_dimensions_next(struct atsc_content_advisory_entry *e, + struct atsc_content_advisory_entry_dimension *pos, + int idx) +{ + uint8_t *next = (uint8_t *) pos + sizeof(struct atsc_content_advisory_entry_dimension); + + if (idx >= e->rated_dimensions) + return NULL; + return (struct atsc_content_advisory_entry_dimension *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/cvct_section.c b/kaffeine/src/input/dvb/lib/libucsi/atsc/cvct_section.c new file mode 100644 index 0000000..6edbc03 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/cvct_section.c @@ -0,0 +1,77 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <libucsi/atsc/cvct_section.h> + +struct atsc_cvct_section *atsc_cvct_section_codec(struct atsc_section_psip *psip) +{ + uint8_t * buf = (uint8_t *) psip; + size_t pos = sizeof(struct atsc_section_psip); + size_t len = section_ext_length(&(psip->ext_head)); + int idx; + + if (len < sizeof(struct atsc_cvct_section)) + return NULL; + struct atsc_cvct_section *cvct = (struct atsc_cvct_section *) psip; + + pos++; + for(idx =0; idx < cvct->num_channels_in_section; idx++) { + if ((pos + sizeof(struct atsc_cvct_channel)) > len) + return NULL; + struct atsc_cvct_channel *channel = (struct atsc_cvct_channel *) (buf+pos); + + pos += 7*2; + + bswap32(buf+pos); + bswap32(buf+pos+4); + bswap16(buf+pos+8); + bswap16(buf+pos+10); + bswap16(buf+pos+12); + bswap16(buf+pos+14); + bswap16(buf+pos+16); + pos+=18; + + if ((pos + channel->descriptors_length) > len) + return NULL; + if (verify_descriptors(buf + pos, channel->descriptors_length)) + return NULL; + + pos += channel->descriptors_length; + } + + if ((pos + sizeof(struct atsc_cvct_section_part2)) > len) + return NULL; + struct atsc_cvct_section_part2 *part2 = (struct atsc_cvct_section_part2 *) (buf+pos); + + bswap16(buf+pos); + pos+=2; + + if ((pos + part2->descriptors_length) > len) + return NULL; + if (verify_descriptors(buf + pos, part2->descriptors_length)) + return NULL; + + pos += part2->descriptors_length; + if (pos != len) + return NULL; + + return (struct atsc_cvct_section *) psip; +} diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/cvct_section.h b/kaffeine/src/input/dvb/lib/libucsi/atsc/cvct_section.h new file mode 100644 index 0000000..c3d418a --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/cvct_section.h @@ -0,0 +1,228 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_ATSC_CVCT_SECTION_H +#define _UCSI_ATSC_CVCT_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/atsc/section.h> + +/** + * atsc_cvct_section structure. + */ +struct atsc_cvct_section { + struct atsc_section_psip head; + + uint8_t num_channels_in_section; + /* struct atsc_cvct_channel channels[] */ + /* struct atsc_cvct_channel_part2 part2 */ +} __ucsi_packed; + +struct atsc_cvct_channel { + uint16_t short_name[7]; // UTF-16 network ordered + EBIT4(uint32_t reserved : 4; , + uint32_t major_channel_number :10; , + uint32_t minor_channel_number :10; , + uint32_t modulation_mode : 8; ); + uint32_t carrier_frequency; + uint16_t channel_TSID; + uint16_t program_number; + EBIT8(uint16_t ETM_location : 2; , + uint16_t access_controlled : 1; , + uint16_t hidden : 1; , + uint16_t path_select : 1; , + uint16_t out_of_band : 1; , + uint16_t hide_guide : 1; , + uint16_t reserved2 : 3; , + uint16_t service_type : 6; ); + uint16_t source_id; + EBIT2(uint16_t reserved3 : 6; , + uint16_t descriptors_length :10; ); + /* struct descriptor descriptors[] */ +} __ucsi_packed; + +struct atsc_cvct_section_part2 { + EBIT2(uint16_t reserved : 6; , + uint16_t descriptors_length :10; ); + /* struct descriptor descriptors[] */ +} __ucsi_packed; + +static inline struct atsc_cvct_channel *atsc_cvct_section_channels_first(struct atsc_cvct_section *cvct); +static inline struct atsc_cvct_channel * + atsc_cvct_section_channels_next(struct atsc_cvct_section *cvct, struct atsc_cvct_channel *pos, int idx); + +/** + * Process a atsc_cvct_section. + * + * @param section Pointer to anj atsc_section_psip structure. + * @return atsc_cvct_section pointer, or NULL on error. + */ +struct atsc_cvct_section *atsc_cvct_section_codec(struct atsc_section_psip *section); + +/** + * Accessor for the transport_stream_id field of a CVCT. + * + * @param cvdt CVDT pointer. + * @return The transport_stream_id. + */ +static inline uint16_t atsc_cvct_section_transport_stream_id(struct atsc_cvct_section *cvct) +{ + return cvct->head.ext_head.table_id_ext; +} + +/** + * Iterator for the tables field in an atsc_cvct_section. + * + * @param mgt atsc_cvct_section pointer. + * @param pos Variable containing a pointer to the current atsc_cvct_channel. + * @param idx Integer used to count which table we in. + */ +#define atsc_cvct_section_channels_for_each(mgt, pos, idx) \ + for ((pos) = atsc_cvct_section_channels_first(mgt), idx=0; \ + (pos); \ + (pos) = atsc_cvct_section_channels_next(mgt, pos, ++idx)) + +/** + * Iterator for the descriptors field in a atsc_cvct_channel structure. + * + * @param table atsc_cvct_channel pointer. + * @param pos Variable containing a pointer to the current descriptor. + */ +#define atsc_cvct_channel_descriptors_for_each(table, pos) \ + for ((pos) = atsc_cvct_channel_descriptors_first(table); \ + (pos); \ + (pos) = atsc_cvct_channel_descriptors_next(table, pos)) + +/** + * Accessor for the second part of an atsc_cvct_section. + * + * @param mgt atsc_cvct_section pointer. + * @return atsc_cvct_section_part2 pointer. + */ +static inline struct atsc_cvct_section_part2 * + atsc_cvct_section_part2(struct atsc_cvct_section *mgt) +{ + int pos = sizeof(struct atsc_cvct_section); + + struct atsc_cvct_channel *cur_table; + int idx; + atsc_cvct_section_channels_for_each(mgt, cur_table, idx) { + pos += sizeof(struct atsc_cvct_channel); + pos += cur_table->descriptors_length; + } + + return (struct atsc_cvct_section_part2 *) (((uint8_t*) mgt) + pos); +} + +/** + * Iterator for the descriptors field in a atsc_cvct_section structure. + * + * @param part2 atsc_cvct_section_part2 pointer. + * @param pos Variable containing a pointer to the current descriptor. + */ +#define atsc_cvct_section_part2_descriptors_for_each(part2, pos) \ + for ((pos) = atsc_cvct_section_part2_descriptors_first(part2); \ + (pos); \ + (pos) = atsc_cvct_section_part2_descriptors_next(part2, pos)) + + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct atsc_cvct_channel * + atsc_cvct_section_channels_first(struct atsc_cvct_section *cvct) +{ + size_t pos = sizeof(struct atsc_cvct_section); + + if (cvct->num_channels_in_section == 0) + return NULL; + + return (struct atsc_cvct_channel*) (((uint8_t *) cvct) + pos); +} + +static inline struct atsc_cvct_channel * + atsc_cvct_section_channels_next(struct atsc_cvct_section *cvct, + struct atsc_cvct_channel *pos, + int idx) +{ + if (idx >= cvct->num_channels_in_section) + return NULL; + + return (struct atsc_cvct_channel *) + (((uint8_t*) pos) + sizeof(struct atsc_cvct_channel) + pos->descriptors_length); +} + +static inline struct descriptor * + atsc_cvct_channel_descriptors_first(struct atsc_cvct_channel *table) +{ + size_t pos = sizeof(struct atsc_cvct_channel); + + if (table->descriptors_length == 0) + return NULL; + + return (struct descriptor*) (((uint8_t *) table) + pos); +} + +static inline struct descriptor * + atsc_cvct_channel_descriptors_next(struct atsc_cvct_channel *table, + struct descriptor *pos) +{ + return next_descriptor((uint8_t*) table + sizeof(struct atsc_cvct_channel), + table->descriptors_length, + pos); +} + +static inline struct descriptor * + atsc_cvct_section_part2_descriptors_first(struct atsc_cvct_section_part2 *part2) +{ + size_t pos = sizeof(struct atsc_cvct_section_part2); + + if (part2->descriptors_length == 0) + return NULL; + + return (struct descriptor*) (((uint8_t *) part2) + pos); +} + +static inline struct descriptor * + atsc_cvct_section_part2_descriptors_next(struct atsc_cvct_section_part2 *part2, + struct descriptor *pos) +{ + return next_descriptor((uint8_t*) part2 + sizeof(struct atsc_cvct_section_part2), + part2->descriptors_length, + pos); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/dcc_arriving_request_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/atsc/dcc_arriving_request_descriptor.h new file mode 100644 index 0000000..af76eac --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/dcc_arriving_request_descriptor.h @@ -0,0 +1,107 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_ATSC_DCC_ARRIVING_REQUEST_DESCRIPTOR +#define _UCSI_ATSC_DCC_ARRIVING_REQUEST_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> + +enum atsc_dcc_arriving_request_type { + DCC_ARRIVAL_TYPE_DEFER_10SEC = 0x01, + DCC_ARRIVAL_TYPE_DEFER = 0x02, +}; + +/** + * atsc_dcc_arriving_request_descriptor structure. + */ +struct atsc_dcc_arriving_request_descriptor { + struct descriptor d; + + uint8_t dcc_arriving_request_type; + uint8_t dcc_arriving_request_text_length; + /* struct atsc_text text[] */ +} __ucsi_packed; + +/** + * Process an atsc_dcc_arriving_request_descriptor. + * + * @param d Generic descriptor pointer. + * @return atsc_dcc_arriving_request_descriptor pointer, or NULL on error. + */ +static inline struct atsc_dcc_arriving_request_descriptor* + atsc_dcc_arriving_request_descriptor_codec(struct descriptor* d) +{ + struct atsc_dcc_arriving_request_descriptor *ret = + (struct atsc_dcc_arriving_request_descriptor *) d; + + if (d->len < 2) + return NULL; + + if (d->len != 2 + ret->dcc_arriving_request_text_length) + return NULL; + + if (atsc_text_validate((uint8_t*) d + sizeof(struct atsc_dcc_arriving_request_descriptor), + ret->dcc_arriving_request_text_length)) + return NULL; + + return (struct atsc_dcc_arriving_request_descriptor*) d; +} + +/** + * Accessor for the text field of an atsc_dcc_arriving_request_descriptor. + * + * @param d atsc_dcc_arriving_request_descriptor pointer. + * @return Pointer to the atsc_text data, or NULL on error. + */ +static inline struct atsc_text* + atsc_dcc_arriving_request_descriptor_text(struct atsc_dcc_arriving_request_descriptor *d) +{ + uint8_t *txt = ((uint8_t*) d) + sizeof(struct atsc_dcc_arriving_request_descriptor); + + return (struct atsc_text*) txt; +} + +/** + * Accessor for the length of the text field of an atsc_dcc_arriving_request_descriptor. + * + * @param d atsc_dcc_arriving_request_descriptor pointer. + * @return The length in bytes. + */ +static inline int + atsc_dcc_arriving_request_descriptor_text_length(struct + atsc_dcc_arriving_request_descriptor *d) +{ + return d->d.len - 2; +} + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/dcc_departing_request_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/atsc/dcc_departing_request_descriptor.h new file mode 100644 index 0000000..851f0cc --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/dcc_departing_request_descriptor.h @@ -0,0 +1,108 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_ATSC_DCC_DEPARTING_REQUEST_DESCRIPTOR +#define _UCSI_ATSC_DCC_DEPARTING_REQUEST_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> + +enum atsc_dcc_departing_request_type { + DCC_DEPART_TYPE_IMMEDIATE = 0x01, + DCC_DEPART_TYPE_DEFER_10SEC = 0x02, + DCC_DEPART_TYPE_DEFER = 0x03, +}; + +/** + * atsc_dcc_departing_request_descriptor structure. + */ +struct atsc_dcc_departing_request_descriptor { + struct descriptor d; + + uint8_t dcc_departing_request_type; + uint8_t dcc_departing_request_text_length; + /* struct atsc_text text[] */ +} __ucsi_packed; + +/** + * Process an atsc_dcc_departing_request_descriptor. + * + * @param d Generic descriptor pointer. + * @return atsc_dcc_departing_request_descriptor pointer, or NULL on error. + */ +static inline struct atsc_dcc_departing_request_descriptor* + atsc_dcc_departing_request_descriptor_codec(struct descriptor* d) +{ + struct atsc_dcc_departing_request_descriptor *ret = + (struct atsc_dcc_departing_request_descriptor *) d; + + if (d->len < 2) + return NULL; + + if (d->len != 2 + ret->dcc_departing_request_text_length) + return NULL; + + if (atsc_text_validate(((uint8_t*) d) + sizeof(struct atsc_dcc_departing_request_descriptor), + ret->dcc_departing_request_text_length)) + return NULL; + + return (struct atsc_dcc_departing_request_descriptor*) d; +} + +/** + * Accessor for the text field of an atsc_dcc_departing_request_descriptor. + * + * @param d atsc_dcc_departing_request_descriptor pointer. + * @return Pointer to the atsc_text data, or NULL on error. + */ +static inline struct atsc_text* + atsc_dcc_departing_request_descriptor_text(struct atsc_dcc_departing_request_descriptor *d) +{ + uint8_t *txt = ((uint8_t*) d) + sizeof(struct atsc_dcc_departing_request_descriptor); + + return (struct atsc_text*) txt; +} + +/** + * Accessor for the length of the text field of an atsc_dcc_departing_request_descriptor. + * + * @param d atsc_dcc_departing_request_descriptor pointer. + * @return The length in bytes. + */ +static inline int + atsc_dcc_departing_request_descriptor_text_length(struct + atsc_dcc_departing_request_descriptor *d) +{ + return d->d.len - 2; +} + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/dccsct_section.c b/kaffeine/src/input/dvb/lib/libucsi/atsc/dccsct_section.c new file mode 100644 index 0000000..59ad069 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/dccsct_section.c @@ -0,0 +1,109 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <libucsi/atsc/dccsct_section.h> + +struct atsc_dccsct_section *atsc_dccsct_section_codec(struct atsc_section_psip *psip) +{ + uint8_t * buf = (uint8_t *) psip; + size_t pos = 0; + size_t len = section_ext_length(&(psip->ext_head)); + int idx; + + if (len < sizeof(struct atsc_dccsct_section)) + return NULL; + struct atsc_dccsct_section *dccsct = (struct atsc_dccsct_section *) psip; + + pos += sizeof(struct atsc_dccsct_section); + for(idx =0; idx < dccsct->updates_defined; idx++) { + if (len < (pos + sizeof(struct atsc_dccsct_update))) + return NULL; + struct atsc_dccsct_update *update = (struct atsc_dccsct_update *) (buf+pos); + + pos += sizeof(struct atsc_dccsct_update); + if (len < (pos + update->update_data_length)) + return NULL; + + switch(update->update_type) { + case ATSC_DCCST_UPDATE_NEW_GENRE: { + int sublen = sizeof(struct atsc_dccsct_update_new_genre); + if (update->update_data_length < sublen) + return NULL; + + if (atsc_text_validate(buf+pos+sublen, update->update_data_length - sublen)) + return NULL; + break; + } + case ATSC_DCCST_UPDATE_NEW_STATE: { + int sublen = sizeof(struct atsc_dccsct_update_new_state); + if (update->update_data_length < sublen) + return NULL; + + if (atsc_text_validate(buf+pos+sublen, update->update_data_length - sublen)) + return NULL; + break; + } + case ATSC_DCCST_UPDATE_NEW_COUNTY: { + int sublen = sizeof(struct atsc_dccsct_update_new_county); + if (update->update_data_length < sublen) + return NULL; + bswap16(buf+pos+1); + + if (atsc_text_validate(buf+pos+sublen, update->update_data_length - sublen)) + return NULL; + break; + } + } + + pos += update->update_data_length; + if (len < (pos + sizeof(struct atsc_dccsct_update_part2))) + return NULL; + struct atsc_dccsct_update_part2 *part2 = (struct atsc_dccsct_update_part2 *) buf + pos; + + bswap16(buf+pos); + + pos += sizeof(struct atsc_dccsct_update_part2); + if (len < (pos + part2->descriptors_length)) + return NULL; + if (verify_descriptors(buf + pos, part2->descriptors_length)) + return NULL; + + pos += part2->descriptors_length; + } + + if (len < (pos + sizeof(struct atsc_dccsct_section_part2))) + return NULL; + struct atsc_dccsct_section_part2 *part2 = (struct atsc_dccsct_section_part2 *) (buf+pos); + + bswap16(buf+pos); + + pos += sizeof(struct atsc_dccsct_section_part2); + if (len < (pos + part2->descriptors_length)) + return NULL; + if (verify_descriptors(buf + pos, part2->descriptors_length)) + return NULL; + + pos += part2->descriptors_length; + if (pos != len) + return NULL; + + return (struct atsc_dccsct_section *) psip; +} diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/dccsct_section.h b/kaffeine/src/input/dvb/lib/libucsi/atsc/dccsct_section.h new file mode 100644 index 0000000..f9f3522 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/dccsct_section.h @@ -0,0 +1,327 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_ATSC_DCCSCT_SECTION_H +#define _UCSI_ATSC_DCCSCT_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/atsc/section.h> +#include <libucsi/atsc/types.h> + +enum atsc_dccst_update_types { + ATSC_DCCST_UPDATE_NEW_GENRE = 0x01, + ATSC_DCCST_UPDATE_NEW_STATE = 0x02, + ATSC_DCCST_UPDATE_NEW_COUNTY = 0x03, +}; + +/** + * atsc_dccsct_section structure. + */ +struct atsc_dccsct_section { + struct atsc_section_psip head; + + uint8_t updates_defined; + /* struct atsc_dccsct_update updates */ + /* struct atsc_dccsct_section_part2 part2 */ +} __ucsi_packed; + +struct atsc_dccsct_update { + uint8_t update_type; + uint8_t update_data_length; + /* struct atsc_dccsct_update_XXX data -- depends on update_type */ + /* struct atsc_dccsct_update_part2 part2 */ +} __ucsi_packed; + +struct atsc_dccsct_update_new_genre { + uint8_t genre_category_code; + /* atsc_text name */ +} __ucsi_packed; + +struct atsc_dccsct_update_new_state { + uint8_t dcc_state_location_code; + /* atsc_text name */ +} __ucsi_packed; + +struct atsc_dccsct_update_new_county { + uint8_t state_code; + EBIT2(uint16_t reserved : 6; , + uint16_t dcc_county_location_code :10; ); + /* atsc_text name */ +} __ucsi_packed; + +struct atsc_dccsct_update_part2 { + EBIT2(uint16_t reserved : 6; , + uint16_t descriptors_length :10; ); + /* struct descriptor descriptors[] */ +} __ucsi_packed; + +struct atsc_dccsct_section_part2 { + EBIT2(uint16_t reserved : 6; , + uint16_t descriptors_length :10; ); + /* struct descriptor descriptors[] */ +} __ucsi_packed; + +/** + * Process an atsc_dccsct_section. + * + * @param section Pointer to an atsc_section_psip structure. + * @return atsc_dccsct_section pointer, or NULL on error. + */ +struct atsc_dccsct_section *atsc_dccsct_section_codec(struct atsc_section_psip *section); + +/** + * Accessor for the dccsct_type field of a dccsct. + * + * @param dccsct dccsct pointer. + * @return The dccsct_type. + */ +static inline uint16_t atsc_dccsct_section_dccsct_type(struct atsc_dccsct_section *dccsct) +{ + return dccsct->head.ext_head.table_id_ext; +} + +/** + * Iterator for the updates field in an atsc_dccsct_section. + * + * @param dccsct atsc_dccsct_section pointer. + * @param pos Variable containing a pointer to the current atsc_dccsct_update. + * @param idx Integer used to count which test we are in. + */ +#define atsc_dccsct_section_updates_for_each(dccsct, pos, idx) \ + for ((pos) = atsc_dccsct_section_updates_first(dccsct), idx=0; \ + (pos); \ + (pos) = atsc_dccsct_section_updates_next(dccsct, pos, ++idx)) + +/** + * Accessor for the data field of a new genre atsc_dccsct_update. + * + * @param update atsc_dccsct_update pointer. + * @return struct atsc_dccsct_update_new_genre pointer. + */ +static inline struct atsc_dccsct_update_new_genre *atsc_dccsct_update_new_genre(struct atsc_dccsct_update *update) +{ + if (update->update_type != ATSC_DCCST_UPDATE_NEW_GENRE) + return NULL; + + return (struct atsc_dccsct_update_new_genre *) + (((uint8_t*) update) + sizeof(struct atsc_dccsct_update)); +} + +/** + * Accessor for the name field of an atsc_dccsct_update_new_genre. + * + * @param update atsc_dccsct_update_new_genre pointer. + * @return text pointer. + */ +static inline struct atsc_text *atsc_dccsct_update_new_genre_name(struct atsc_dccsct_update *update) +{ + if ((update->update_data_length - 1) == 0) + return NULL; + + return (struct atsc_text *) + (((uint8_t*) update) + sizeof(struct atsc_dccsct_update_new_genre)); +} + +/** + * Accessor for the data field of a new state atsc_dccsct_update. + * + * @param update atsc_dccsct_update pointer. + * @return struct atsc_dccsct_update_new_state pointer. + */ +static inline struct atsc_dccsct_update_new_state * + atsc_dccsct_update_new_state(struct atsc_dccsct_update *update) +{ + if (update->update_type != ATSC_DCCST_UPDATE_NEW_STATE) + return NULL; + + return (struct atsc_dccsct_update_new_state *) + (((uint8_t*) update) + sizeof(struct atsc_dccsct_update)); +} + +/** + * Accessor for the name field of an atsc_dccsct_update_new_state. + * + * @param update atsc_dccsct_update_new_state pointer. + * @return text pointer. + */ +static inline struct atsc_text *atsc_dccsct_update_new_state_name(struct atsc_dccsct_update *update) +{ + if ((update->update_data_length - 1) == 0) + return NULL; + + return (struct atsc_text *) + (((uint8_t*) update) + sizeof(struct atsc_dccsct_update_new_state)); +} + +/** + * Accessor for the data field of a new county atsc_dccsct_update. + * + * @param update atsc_dccsct_update pointer. + * @return struct atsc_dccsct_update_new_county pointer. + */ +static inline struct atsc_dccsct_update_new_county * + atsc_dccsct_update_new_county(struct atsc_dccsct_update *update) +{ + if (update->update_type != ATSC_DCCST_UPDATE_NEW_COUNTY) + return NULL; + + return (struct atsc_dccsct_update_new_county *) + (((uint8_t*) update) + sizeof(struct atsc_dccsct_update)); +} + +/** + * Accessor for the name field of an atsc_dccsct_update_new_county. + * + * @param update atsc_dccsct_update_new_county pointer. + * @return text pointer. + */ +static inline struct atsc_text *atsc_dccsct_update_new_county_name(struct atsc_dccsct_update *update) +{ + if ((update->update_data_length - 3) == 0) + return NULL; + + return (struct atsc_text*) + (((uint8_t*) update) + sizeof(struct atsc_dccsct_update_new_county)); +} + +/** + * Accessor for the part2 field of an atsc_dccsct_update. + * + * @param update atsc_dccsct_update pointer. + * @return struct atsc_dccsct_test_part2 pointer. + */ +static inline struct atsc_dccsct_update_part2 *atsc_dccsct_update_part2(struct atsc_dccsct_update *update) +{ + int pos = sizeof(struct atsc_dccsct_update); + pos += update->update_data_length; + + return (struct atsc_dccsct_update_part2 *) (((uint8_t*) update) + pos); +} + +/** + * Iterator for the descriptors field in an atsc_dccsct_update_part2 structure. + * + * @param part2 atsc_dccsct_update_part2 pointer. + * @param pos Variable containing a pointer to the current descriptor. + */ +#define atsc_dccsct_update_part2_descriptors_for_each(part2, pos) \ + for ((pos) = atsc_dccsct_update_part2_descriptors_first(part2); \ + (pos); \ + (pos) = atsc_dccsct_update_part2_descriptors_next(part2, pos)) + +/** + * Iterator for the descriptors field in a atsc_dccsct_section_part2 structure. + * + * @param part2 atsc_dccsct_section_part2 pointer. + * @param pos Variable containing a pointer to the current descriptor. + */ +#define atsc_dccsct_section_part2_descriptors_for_each(part2, pos) \ + for ((pos) = atsc_dccsct_section_part2_descriptors_first(part2); \ + (pos); \ + (pos) = atsc_dccsct_section_part2_descriptors_next(part2, pos)) + + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct atsc_dccsct_update * + atsc_dccsct_section_updates_first(struct atsc_dccsct_section *dccsct) +{ + size_t pos = sizeof(struct atsc_dccsct_section); + + if (dccsct->updates_defined == 0) + return NULL; + + return (struct atsc_dccsct_update*) (((uint8_t *) dccsct) + pos); +} + +static inline struct atsc_dccsct_update* + atsc_dccsct_section_updates_next(struct atsc_dccsct_section *dccsct, + struct atsc_dccsct_update *pos, + int idx) +{ + if (idx >= dccsct->updates_defined) + return NULL; + + struct atsc_dccsct_update_part2 *part2 = atsc_dccsct_update_part2(pos); + int len = sizeof(struct atsc_dccsct_update_part2); + len += part2->descriptors_length; + + return (struct atsc_dccsct_update *) (((uint8_t*) part2) + len); +} + +static inline struct descriptor * + atsc_dccsct_update_part2_descriptors_first(struct atsc_dccsct_update_part2 *part2) +{ + size_t pos = sizeof(struct atsc_dccsct_update_part2); + + if (part2->descriptors_length == 0) + return NULL; + + return (struct descriptor*) (((uint8_t *) part2) + pos); +} + +static inline struct descriptor * + atsc_dccsct_update_part2_descriptors_next(struct atsc_dccsct_update_part2 *part2, + struct descriptor *pos) +{ + return next_descriptor((uint8_t*) part2 + sizeof(struct atsc_dccsct_update_part2), + part2->descriptors_length, + pos); +} + +static inline struct descriptor * + atsc_dccsct_section_part2_descriptors_first(struct atsc_dccsct_section_part2 *part2) +{ + size_t pos = sizeof(struct atsc_dccsct_section_part2); + + if (part2->descriptors_length == 0) + return NULL; + + return (struct descriptor*) (((uint8_t *) part2) + pos); +} + +static inline struct descriptor * + atsc_dccsct_section_part2_descriptors_next(struct atsc_dccsct_section_part2 *part2, + struct descriptor *pos) +{ + return next_descriptor((uint8_t*) part2 + sizeof(struct atsc_dccsct_section_part2), + part2->descriptors_length, + pos); +} + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/dcct_section.c b/kaffeine/src/input/dvb/lib/libucsi/atsc/dcct_section.c new file mode 100644 index 0000000..7d0b83b --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/dcct_section.c @@ -0,0 +1,96 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <libucsi/atsc/dcct_section.h> + +struct atsc_dcct_section *atsc_dcct_section_codec(struct atsc_section_psip *psip) +{ + uint8_t * buf = (uint8_t *) psip; + size_t pos = 0; + size_t len = section_ext_length(&(psip->ext_head)); + int testidx; + int termidx; + + if (len < sizeof(struct atsc_dcct_section)) + return NULL; + struct atsc_dcct_section *dcct = (struct atsc_dcct_section *) psip; + + pos += sizeof(struct atsc_dcct_section); + for(testidx =0; testidx < dcct->dcc_test_count; testidx++) { + if (len < (pos + sizeof(struct atsc_dcct_test))) + return NULL; + struct atsc_dcct_test *test = (struct atsc_dcct_test *) (buf+pos); + + bswap24(buf+pos); + bswap24(buf+pos+3); + bswap32(buf+pos+6); + bswap32(buf+pos+10); + + pos += sizeof(struct atsc_dcct_test); + for(termidx =0; termidx < test->dcc_term_count; termidx++) { + if (len < (pos + sizeof(struct atsc_dcct_term))) + return NULL; + struct atsc_dcct_term *term = (struct atsc_dcct_term *) (buf+pos); + + bswap64(buf+pos+1); + bswap16(buf+pos+9); + + pos += sizeof(struct atsc_dcct_term); + if (len < (pos + term->descriptors_length)) + return NULL; + if (verify_descriptors(buf + pos, term->descriptors_length)) + return NULL; + + pos += term->descriptors_length; + } + + if (len < (pos + sizeof(struct atsc_dcct_test_part2))) + return NULL; + struct atsc_dcct_test_part2 *part2 = (struct atsc_dcct_test_part2 *) (buf+pos); + + bswap16(buf+pos); + + pos += sizeof(struct atsc_dcct_test_part2); + if (len < (pos + part2->descriptors_length)) + return NULL; + if (verify_descriptors(buf + pos, part2->descriptors_length)) + return NULL; + pos += part2->descriptors_length; + } + + if (len < (pos + sizeof(struct atsc_dcct_section_part2))) + return NULL; + struct atsc_dcct_section_part2 *part2 = (struct atsc_dcct_section_part2 *) (buf+pos); + + bswap16(buf+pos); + + pos += sizeof(struct atsc_dcct_section_part2); + if (len < (pos + part2->descriptors_length)) + return NULL; + if (verify_descriptors(buf + pos, part2->descriptors_length)) + return NULL; + + pos += part2->descriptors_length; + if (pos != len) + return NULL; + + return (struct atsc_dcct_section *) psip; +} diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/dcct_section.h b/kaffeine/src/input/dvb/lib/libucsi/atsc/dcct_section.h new file mode 100644 index 0000000..647bd4b --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/dcct_section.h @@ -0,0 +1,380 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_ATSC_DCCT_SECTION_H +#define _UCSI_ATSC_DCCT_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/atsc/section.h> +#include <libucsi/atsc/types.h> + +enum atsc_dcc_context { + ATSC_DCC_CONTEXT_TEMPORARY_RETUNE = 0, + ATSC_DCC_CONTEXT_CHANNEL_REDIRECT = 1, +}; + +enum atsc_dcc_selection_type { + ATSC_DCC_SELECTION_UNCONDITIONAL_CHANNEL_CHANGE = 0x00, + ATSC_DCC_SELECTION_NUMERIC_POSTAL_CODE_INCLUSION = 0x01, + ATSC_DCC_SELECTION_ALPHANUMERIC_POSTAL_CODE_INCLUSION = 0x02, + ATSC_DCC_SELECTION_DEMOGRAPHIC_CATEGORY_ONE_OR_MORE = 0x05, + ATSC_DCC_SELECTION_DEMOGRAPHIC_CATEGORY_ALL = 0x06, + ATSC_DCC_SELECTION_GENRE_CATEGORY_ONE_OR_MORE = 0x07, + ATSC_DCC_SELECTION_GENRE_CATEGORY_ALL = 0x08, + ATSC_DCC_SELECTION_CANNOT_BE_AUTHORIZED = 0x09, + ATSC_DCC_SELECTION_GEOGRAPHIC_LOCATION_INCLUSION = 0x0c, + ATSC_DCC_SELECTION_RATING_BLOCKED = 0x0d, + ATSC_DCC_SELECTION_RETURN_TO_ORIGINAL_CHANNEL = 0x0f, + ATSC_DCC_SELECTION_NUMERIC_POSTAL_CODE_EXCLUSION = 0x11, + ATSC_DCC_SELECTION_ALPHANUMERIC_POSTAL_CODE_EXCLUSION = 0x12, + ATSC_DCC_SELECTION_DEMOGRAPHIC_CATEGORY_NOT_ONE_OR_MORE = 0x15, + ATSC_DCC_SELECTION_DEMOGRAPHIC_CATEGORY_NOT_ALL = 0x16, + ATSC_DCC_SELECTION_GENRE_CATEGORY_NOT_ONE_OR_MORE = 0x17, + ATSC_DCC_SELECTION_GENRE_CATEGORY_NOT_ALL = 0x18, + ATSC_DCC_SELECTION_GEOGRAPHIC_LOCATION_EXCLUSION = 0x1c, + ATSC_DCC_SELECTION_VIEWER_DIRECT_SELECT_A = 0x20, + ATSC_DCC_SELECTION_VIEWER_DIRECT_SELECT_B = 0x21, + ATSC_DCC_SELECTION_VIEWER_DIRECT_SELECT_C = 0x22, + ATSC_DCC_SELECTION_VIEWER_DIRECT_SELECT_D = 0x23, +}; + +/** + * atsc_dcct_section structure. + */ +struct atsc_dcct_section { + struct atsc_section_psip head; + + uint8_t dcc_test_count; + /* struct atsc_dcct_test tests */ + /* struct atsc_dcct_section_part2 part2 */ +} __ucsi_packed; + +struct atsc_dcct_test { + EBIT4(uint32_t dcc_context : 1; , + uint32_t reserved : 3; , + uint32_t dcc_from_major_channel_number :10; , + uint32_t dcc_from_minor_channel_number :10; ); + EBIT3(uint32_t reserved1 : 4; , + uint32_t dcc_to_major_channel_number :10; , + uint32_t dcc_to_minor_channel_number :10; ); + atsctime_t start_time; + atsctime_t end_time; + uint8_t dcc_term_count; + /* struct atsc_dcct_term terms */ + /* struct atsc_dcct_test_part2 part2 */ +} __ucsi_packed; + +struct atsc_dcct_term { + uint8_t dcc_selection_type; + uint64_t dcc_selection_id; + EBIT2(uint16_t reserved : 6; , + uint16_t descriptors_length :10; ); + /* struct descriptor descriptors[] */ +} __ucsi_packed; + +struct atsc_dcct_test_part2 { + EBIT2(uint16_t reserved : 6; , + uint16_t descriptors_length :10; ); + /* struct descriptor descriptors[] */ +} __ucsi_packed; + +struct atsc_dcct_section_part2 { + EBIT2(uint16_t reserved : 6; , + uint16_t descriptors_length :10; ); + /* struct descriptor descriptors[] */ +} __ucsi_packed; + +static inline struct atsc_dcct_test * + atsc_dcct_section_tests_first(struct atsc_dcct_section *dcct); +static inline struct atsc_dcct_test * + atsc_dcct_section_tests_next(struct atsc_dcct_section *dcct, + struct atsc_dcct_test *pos, + int idx); +static inline struct atsc_dcct_term * + atsc_dcct_test_terms_first(struct atsc_dcct_test *test); +static inline struct atsc_dcct_term * + atsc_dcct_test_terms_next(struct atsc_dcct_test *test, + struct atsc_dcct_term *pos, + int idx); + + +/** + * Process an atsc_dcct_section. + * + * @param section Pointer to an atsc_section_psip structure. + * @return atsc_dcct_section pointer, or NULL on error. + */ +struct atsc_dcct_section *atsc_dcct_section_codec(struct atsc_section_psip *section); + +/** + * Accessor for the dcc_subtype field of a dcct. + * + * @param dcct dcct pointer. + * @return The dcc_subtype. + */ +static inline uint8_t atsc_dcct_section_dcc_subtype(struct atsc_dcct_section *dcct) +{ + return dcct->head.ext_head.table_id_ext >> 8; +} + +/** + * Accessor for the dcc_id field of a dcct. + * + * @param dcct dcct pointer. + * @return The dcc_id. + */ +static inline uint8_t atsc_dcct_section_dcc_id(struct atsc_dcct_section *dcct) +{ + return dcct->head.ext_head.table_id_ext & 0xff; +} + +/** + * Iterator for the tests field in an atsc_dcct_section. + * + * @param dcct atsc_dcct_section pointer. + * @param pos Variable containing a pointer to the current atsc_dcct_test. + * @param idx Integer used to count which test we are in. + */ +#define atsc_dcct_section_tests_for_each(dcct, pos, idx) \ + for ((pos) = atsc_dcct_section_tests_first(dcct), idx=0; \ + (pos); \ + (pos) = atsc_dcct_section_tests_next(dcct, pos, ++idx)) + +/** + * Iterator for the terms field in an atsc_dcct_test. + * + * @param test atsc_dcct_test pointer. + * @param pos Variable containing a pointer to the current atsc_dcct_term. + * @param idx Integer used to count which test we are in. + */ +#define atsc_dcct_test_terms_for_each(test, pos, idx) \ + for ((pos) = atsc_dcct_test_terms_first(test), idx=0; \ + (pos); \ + (pos) = atsc_dcct_test_terms_next(test, pos, ++idx)) + +/** + * Iterator for the descriptors field in a atsc_dcct_term structure. + * + * @param term atsc_dcct_term pointer. + * @param pos Variable containing a pointer to the current descriptor. + */ +#define atsc_dcct_term_descriptors_for_each(term, pos) \ + for ((pos) = atsc_dcct_term_descriptors_first(term); \ + (pos); \ + (pos) = atsc_dcct_term_descriptors_next(term, pos)) + +/** + * Accessor for the part2 field of an atsc_dcct_test. + * + * @param test atsc_dcct_test pointer. + * @return struct atsc_dcct_test_part2 pointer. + */ +static inline struct atsc_dcct_test_part2 *atsc_dcct_test_part2(struct atsc_dcct_test *test) +{ + int pos = sizeof(struct atsc_dcct_test); + + struct atsc_dcct_term *cur_term; + int idx; + atsc_dcct_test_terms_for_each(test, cur_term, idx) { + pos += sizeof(struct atsc_dcct_term); + pos += cur_term->descriptors_length; + } + + return (struct atsc_dcct_test_part2 *) (((uint8_t*) test) + pos); +} + +/** + * Iterator for the descriptors field in a atsc_dcct_test_part2 structure. + * + * @param term atsc_dcct_test_part2 pointer. + * @param pos Variable containing a pointer to the current descriptor. + */ +#define atsc_dcct_test_part2_descriptors_for_each(part2, pos) \ + for ((pos) = atsc_dcct_test_part2_descriptors_first(part2); \ + (pos); \ + (pos) = atsc_dcct_test_part2_descriptors_next(part2, pos)) + +/** + * Accessor for the part2 field of an atsc_dcct_section. + * + * @param dcct atsc_dcct_section pointer. + * @return struct atsc_dcct_section_part2 pointer. + */ +static inline struct atsc_dcct_section_part2 *atsc_dcct_section_part2(struct atsc_dcct_section *dcct) +{ + int pos = sizeof(struct atsc_dcct_section); + + struct atsc_dcct_test *cur_test; + int testidx; + atsc_dcct_section_tests_for_each(dcct, cur_test, testidx) { + struct atsc_dcct_test_part2 *part2 = atsc_dcct_test_part2(cur_test); + pos += ((uint8_t*) part2 - (uint8_t*) cur_test); + + pos += sizeof(struct atsc_dcct_test_part2); + pos += part2->descriptors_length; + } + + return (struct atsc_dcct_section_part2 *) (((uint8_t*) dcct) + pos); +} + +/** + * Iterator for the descriptors field in a atsc_dcct_section_part2 structure. + * + * @param part2 atsc_dcct_section_part2 pointer. + * @param pos Variable containing a pointer to the current descriptor. + */ +#define atsc_dcct_section_part2_descriptors_for_each(part2, pos) \ + for ((pos) = atsc_dcct_section_part2_descriptors_first(part2); \ + (pos); \ + (pos) = atsc_dcct_section_part2_descriptors_next(part2, pos)) + + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct atsc_dcct_test * + atsc_dcct_section_tests_first(struct atsc_dcct_section *dcct) +{ + size_t pos = sizeof(struct atsc_dcct_section); + + if (dcct->dcc_test_count == 0) + return NULL; + + return (struct atsc_dcct_test*) (((uint8_t *) dcct) + pos); +} + +static inline struct atsc_dcct_test * + atsc_dcct_section_tests_next(struct atsc_dcct_section *dcct, + struct atsc_dcct_test *pos, + int idx) +{ + if (idx >= dcct->dcc_test_count) + return NULL; + + struct atsc_dcct_test_part2 *part2 = atsc_dcct_test_part2(pos); + int len = sizeof(struct atsc_dcct_test_part2); + len += part2->descriptors_length; + + return (struct atsc_dcct_test *) (((uint8_t*) part2) + len); +} + +static inline struct atsc_dcct_term * + atsc_dcct_test_terms_first(struct atsc_dcct_test *test) +{ + size_t pos = sizeof(struct atsc_dcct_test); + + if (test->dcc_term_count == 0) + return NULL; + + return (struct atsc_dcct_term*) (((uint8_t *) test) + pos); +} + +static inline struct atsc_dcct_term * + atsc_dcct_test_terms_next(struct atsc_dcct_test *test, + struct atsc_dcct_term *pos, + int idx) +{ + if (idx >= test->dcc_term_count) + return NULL; + + int len = sizeof(struct atsc_dcct_term); + len += pos->descriptors_length; + + return (struct atsc_dcct_term *) (((uint8_t*) pos) + len); +} + +static inline struct descriptor * + atsc_dcct_term_descriptors_first(struct atsc_dcct_term *term) +{ + size_t pos = sizeof(struct atsc_dcct_term); + + if (term->descriptors_length == 0) + return NULL; + + return (struct descriptor*) (((uint8_t *) term) + pos); +} + +static inline struct descriptor * + atsc_dcct_term_descriptors_next(struct atsc_dcct_term *term, + struct descriptor *pos) +{ + return next_descriptor((uint8_t*) term + sizeof(struct atsc_dcct_term), + term->descriptors_length, + pos); +} + +static inline struct descriptor * + atsc_dcct_test_part2_descriptors_first(struct atsc_dcct_test_part2 *part2) +{ + size_t pos = sizeof(struct atsc_dcct_test_part2); + + if (part2->descriptors_length == 0) + return NULL; + + return (struct descriptor*) (((uint8_t *) part2) + pos); +} + +static inline struct descriptor * + atsc_dcct_test_part2_descriptors_next(struct atsc_dcct_test_part2 *part2, + struct descriptor *pos) +{ + return next_descriptor((uint8_t*) part2 + sizeof(struct atsc_dcct_test_part2), + part2->descriptors_length, + pos); +} + +static inline struct descriptor * + atsc_dcct_section_part2_descriptors_first(struct atsc_dcct_section_part2 *part2) +{ + size_t pos = sizeof(struct atsc_dcct_section_part2); + + if (part2->descriptors_length == 0) + return NULL; + + return (struct descriptor*) (((uint8_t *) part2) + pos); +} + +static inline struct descriptor * + atsc_dcct_section_part2_descriptors_next(struct atsc_dcct_section_part2 *part2, + struct descriptor *pos) +{ + return next_descriptor((uint8_t*) part2 + sizeof(struct atsc_dcct_section_part2), + part2->descriptors_length, + pos); +} + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/atsc/descriptor.h index a18b29d..a57176a 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/atsc/descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/descriptor.h @@ -28,39 +28,37 @@ extern "C" #endif #include <libucsi/endianops.h> +#include <libucsi/atsc/stuffing_descriptor.h> +#include <libucsi/atsc/ac3_descriptor.h> +#include <libucsi/atsc/caption_service_descriptor.h> +#include <libucsi/atsc/component_name_descriptor.h> +#include <libucsi/atsc/content_advisory_descriptor.h> +#include <libucsi/atsc/dcc_arriving_request_descriptor.h> +#include <libucsi/atsc/dcc_departing_request_descriptor.h> +#include <libucsi/atsc/extended_channel_name_descriptor.h> +#include <libucsi/atsc/genre_descriptor.h> +#include <libucsi/atsc/rc_descriptor.h> +#include <libucsi/atsc/service_location_descriptor.h> +#include <libucsi/atsc/time_shifted_service_descriptor.h> /** * Enumeration of ATSC descriptor tags. */ enum atsc_descriptor_tag { - -/* A 52/A describes a - * dtag_atsc_ac3_registration = 0x05, */ - -/* A90 describes a - * dtag_atsc_association_tag = 0x14, */ - dtag_atsc_stuffing = 0x80, dtag_atsc_ac3_audio = 0x81, dtag_atsc_caption_service = 0x86, dtag_atsc_content_advisory = 0x87, - dtag_atsc_ca = 0x88, dtag_atsc_extended_channel_name = 0xa0, dtag_atsc_service_location = 0xa1, dtag_atsc_time_shifted_service = 0xa2, dtag_atsc_component_name = 0xa3, - dtag_atsc_data_service = 0xa4, - dtag_atsc_pid_count = 0xa5, - dtag_atsc_download = 0xa6, - dtag_atsc_MPE = 0xa7, dtag_atsc_dcc_departing_request = 0xa8, dtag_atsc_dcc_arriving_request = 0xa9, dtag_atsc_redistribution_control = 0xaa, - dtag_atsc_dcc_location_code = 0xab, dtag_atsc_private_information = 0xad, - dtag_atsc_module_link = 0xb4, - dtag_atsc_crc32 = 0xb5, - dtag_atsc_group_link = 0xb8, + dtag_atsc_content_identifier = 0xb6, + dtag_atsc_genre = 0xab, }; #ifdef __cplusplus diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/eit_section.c b/kaffeine/src/input/dvb/lib/libucsi/atsc/eit_section.c new file mode 100644 index 0000000..48cdda6 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/eit_section.c @@ -0,0 +1,71 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <libucsi/atsc/eit_section.h> + +struct atsc_eit_section *atsc_eit_section_codec(struct atsc_section_psip *psip) +{ + uint8_t * buf = (uint8_t *) psip; + size_t pos = 0; + size_t len = section_ext_length(&(psip->ext_head)); + int idx; + + if (len < sizeof(struct atsc_eit_section)) + return NULL; + struct atsc_eit_section *eit = (struct atsc_eit_section *) psip; + + pos += sizeof(struct atsc_eit_section); + for(idx =0; idx < eit->num_events_in_section; idx++) { + if (len < (pos + sizeof(struct atsc_eit_event))) + return NULL; + struct atsc_eit_event *event = (struct atsc_eit_event *) (buf+pos); + + bswap16(buf+pos); + bswap32(buf+pos+2); + bswap32(buf+pos+6); + + pos += sizeof(struct atsc_eit_event); + if (len < (pos + event->title_length)) + return NULL; + if (atsc_text_validate(buf+pos, event->title_length)) + return NULL; + + pos += event->title_length; + if (len < (pos + sizeof(struct atsc_eit_event_part2))) + return NULL; + struct atsc_eit_event_part2 *part2 = (struct atsc_eit_event_part2 *) (buf+pos); + + bswap16(buf+pos); + + pos += sizeof(struct atsc_eit_event_part2); + if (len < (pos + part2->descriptors_length)) + return NULL; + + if (verify_descriptors(buf + pos, part2->descriptors_length)) + return NULL; + pos += part2->descriptors_length; + } + + if (pos != len) + return NULL; + + return (struct atsc_eit_section *) psip; +} diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/eit_section.h b/kaffeine/src/input/dvb/lib/libucsi/atsc/eit_section.h new file mode 100644 index 0000000..84bef16 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/eit_section.h @@ -0,0 +1,191 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_ATSC_EIT_SECTION_H +#define _UCSI_ATSC_EIT_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/atsc/section.h> +#include <libucsi/atsc/types.h> + +/** + * atsc_eit_section structure. + */ +struct atsc_eit_section { + struct atsc_section_psip head; + + uint8_t num_events_in_section; + /* struct atsc_eit_event events[] */ +} __ucsi_packed; + +struct atsc_eit_event { + EBIT2(uint16_t reserved : 2; , + uint16_t event_id :14; ); + atsctime_t start_time; + EBIT4(uint32_t reserved1 : 2; , + uint32_t ETM_location : 2; , + uint32_t length_in_seconds :20; , + uint32_t title_length : 8; ); + /* struct atsc_text title_text */ + /* struct atsc_eit_event_part2 part2 */ +} __ucsi_packed; + +struct atsc_eit_event_part2 { + EBIT2(uint16_t reserved : 4; , + uint16_t descriptors_length :12; ); + /* struct descriptor descriptors[] */ +} __ucsi_packed; + + +/** + * Process a atsc_eit_section. + * + * @param section Pointer to an atsc_section_psip structure. + * @return atsc_eit_section pointer, or NULL on error. + */ +struct atsc_eit_section *atsc_eit_section_codec(struct atsc_section_psip *section); + +/** + * Accessor for the source_id field of an EIT. + * + * @param eit EIT pointer. + * @return The source_id . + */ +static inline uint16_t atsc_eit_section_source_id(struct atsc_eit_section *eit) +{ + return eit->head.ext_head.table_id_ext; +} + +/** + * Iterator for the events field in an atsc_eit_section. + * + * @param eit atsc_eit_section pointer. + * @param pos Variable containing a pointer to the current atsc_eit_event. + * @param idx Integer used to count which event we are in. + */ +#define atsc_eit_section_events_for_each(eit, pos, idx) \ + for ((pos) = atsc_eit_section_events_first(eit), idx=0; \ + (pos); \ + (pos) = atsc_eit_section_events_next(eit, pos, ++idx)) + +/** + * Accessor for the title_text field of an atsc_eit_event. + * + * @param event atsc_eit_event pointer. + * @return struct atsc_text pointer, or NULL on error. + */ +static inline struct atsc_text *atsc_eit_event_name_title_text(struct atsc_eit_event *event) +{ + if (event->title_length == 0) + return NULL; + + return (struct atsc_text*)(((uint8_t*) event) + sizeof(struct atsc_eit_event)); +} + +/** + * Accessor for the part2 field of an atsc_eit_event. + * + * @param event atsc_eit_event pointer. + * @return struct atsc_eit_event_part2 pointer. + */ +static inline struct atsc_eit_event_part2 *atsc_eit_event_part2(struct atsc_eit_event *event) +{ + return (struct atsc_eit_event_part2 *) + (((uint8_t*) event) + sizeof(struct atsc_eit_event) + event->title_length); +} + +/** + * Iterator for the descriptors field in a atsc_eit_section structure. + * + * @param part2 atsc_eit_event_part2 pointer. + * @param pos Variable containing a pointer to the current descriptor. + */ +#define atsc_eit_event_part2_descriptors_for_each(part2, pos) \ + for ((pos) = atsc_eit_event_part2_descriptors_first(part2); \ + (pos); \ + (pos) = atsc_eit_event_part2_descriptors_next(part2, pos)) + + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct atsc_eit_event * + atsc_eit_section_events_first(struct atsc_eit_section *eit) +{ + size_t pos = sizeof(struct atsc_eit_section); + + if (eit->num_events_in_section == 0) + return NULL; + + return (struct atsc_eit_event*) (((uint8_t *) eit) + pos); +} + +static inline struct atsc_eit_event * + atsc_eit_section_events_next(struct atsc_eit_section *eit, + struct atsc_eit_event *pos, + int idx) +{ + if (idx >= eit->num_events_in_section) + return NULL; + + struct atsc_eit_event_part2 *part2 = atsc_eit_event_part2(pos); + int len = sizeof(struct atsc_eit_event_part2); + len += part2->descriptors_length; + + return (struct atsc_eit_event *) (((uint8_t*) part2) + len); +} + +static inline struct descriptor * + atsc_eit_event_part2_descriptors_first(struct atsc_eit_event_part2 *part2) +{ + size_t pos = sizeof(struct atsc_eit_event_part2); + + if (part2->descriptors_length == 0) + return NULL; + + return (struct descriptor*) (((uint8_t *) part2) + pos); +} + +static inline struct descriptor * + atsc_eit_event_part2_descriptors_next(struct atsc_eit_event_part2 *part2, + struct descriptor *pos) +{ + return next_descriptor((uint8_t*) part2 + sizeof(struct atsc_eit_event_part2), + part2->descriptors_length, + pos); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/ett_section.c b/kaffeine/src/input/dvb/lib/libucsi/atsc/ett_section.c new file mode 100644 index 0000000..ab2ff9c --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/ett_section.c @@ -0,0 +1,42 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <libucsi/atsc/ett_section.h> +#include <libucsi/atsc/types.h> + +struct atsc_ett_section *atsc_ett_section_codec(struct atsc_section_psip *psip) +{ + uint8_t * buf = (uint8_t *) psip; + size_t pos = sizeof(struct atsc_section_psip); + size_t len = section_ext_length(&(psip->ext_head)); + + if (len < sizeof(struct atsc_ett_section)) + return NULL; + + bswap32(buf + pos); + pos += 4; + + if (atsc_text_validate(buf + pos, + section_ext_length(&psip->ext_head) - sizeof(struct atsc_ett_section))) + return NULL; + + return (struct atsc_ett_section *) psip; +} diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/ett_section.h b/kaffeine/src/input/dvb/lib/libucsi/atsc/ett_section.h new file mode 100644 index 0000000..e2bb510 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/ett_section.h @@ -0,0 +1,91 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_ATSC_ETT_SECTION_H +#define _UCSI_ATSC_ETT_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/atsc/section.h> + +enum atsc_etm_type { + ATSC_ETM_CHANNEL = 0x00, + ATSC_ETM_EVENT = 0x02, +}; + +/** + * atsc_ett_section structure. + */ +struct atsc_ett_section { + struct atsc_section_psip head; + + EBIT3(uint32_t ETM_source_id :16; , + uint32_t ETM_sub_id :14; , + uint32_t ETM_type : 2; ); + /* struct atsc_text extended_text_message */ +} __ucsi_packed; + +/** + * Process a atsc_ett_section. + * + * @param section Pointer to an atsc_section_psip structure. + * @return atsc_ett_section pointer, or NULL on error. + */ +struct atsc_ett_section *atsc_ett_section_codec(struct atsc_section_psip *section); + +/** + * Accessor for the extended_text_message part of an atsc_ett_section. + * + * @param ett atsc_ett_section pointer. + * @return atsc_text pointer, or NULL on error. + */ +static inline struct atsc_text* + atsc_ett_section_extended_text_message(struct atsc_ett_section *ett) +{ + int pos = sizeof(struct atsc_ett_section); + int len = section_ext_length(&ett->head.ext_head) - sizeof(struct atsc_ett_section); + + if (len == 0) + return NULL; + + return (struct atsc_text*)(((uint8_t*) ett) + pos); +} + +/** + * Accessor for the extended_text_message part of an atsc_ett_section. + * + * @param ett atsc_ett_section pointer. + * @return The length. + */ +static inline int + atsc_ett_section_extended_text_message_length(struct atsc_ett_section *ett) +{ + return section_ext_length(&ett->head.ext_head) - sizeof(struct atsc_ett_section); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/extended_channel_name_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/atsc/extended_channel_name_descriptor.h new file mode 100644 index 0000000..d0b714b --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/extended_channel_name_descriptor.h @@ -0,0 +1,92 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_ATSC_EXTENDED_CHANNEL_NAME_DESCRIPTOR +#define _UCSI_ATSC_EXTENDED_CHANNEL_NAME_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> +#include <libucsi/atsc/types.h> + +/** + * atsc_extended_channel_name_descriptor structure. + */ +struct atsc_extended_channel_name_descriptor { + struct descriptor d; + + /* struct atsc_text text[] */ +} __ucsi_packed; + +/** + * Process an atsc_extended_channel_name_descriptor. + * + * @param d Generic descriptor pointer. + * @return atsc_extended_channel_name_descriptor pointer, or NULL on error. + */ +static inline struct atsc_extended_channel_name_descriptor* + atsc_extended_channel_name_descriptor_codec(struct descriptor* d) +{ + if (atsc_text_validate(((uint8_t*) d) + sizeof(struct atsc_extended_channel_name_descriptor), + d->len)) + return NULL; + + return (struct atsc_extended_channel_name_descriptor*) d; +} + +/** + * Accessor for the text field of an atsc_extended_channel_name_descriptor. + * + * @param d atsc_extended_channel_name_descriptor pointer. + * @return Pointer to the atsc_text data, or NULL on error. + */ +static inline struct atsc_text* + atsc_extended_channel_name_descriptor_text(struct atsc_extended_channel_name_descriptor *d) +{ + uint8_t *txt = ((uint8_t*) d) + sizeof(struct atsc_extended_channel_name_descriptor); + + return (struct atsc_text*) txt; +} + +/** + * Accessor for the length of the text field of an atsc_extended_channel_name_descriptor. + * + * @param d atsc_extended_channel_name_descriptor pointer. + * @return The length in bytes. + */ +static inline int + atsc_extended_channel_name_descriptor_text_length(struct + atsc_extended_channel_name_descriptor *d) +{ + return d->d.len; +} + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/genre_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/atsc/genre_descriptor.h new file mode 100644 index 0000000..a6fc542 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/genre_descriptor.h @@ -0,0 +1,82 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_ATSC_GENRE_DESCRIPTOR +#define _UCSI_ATSC_GENRE_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> + +/** + * atsc_genre_descriptor structure. + */ +struct atsc_genre_descriptor { + struct descriptor d; + + EBIT2(uint8_t reserved : 3; , + uint8_t attribute_count : 5; ); + /* uint8_t attributes[] */ +} __ucsi_packed; + +/** + * Process an atsc_genre_descriptor. + * + * @param d Generic descriptor pointer. + * @return atsc_genre_descriptor pointer, or NULL on error. + */ +static inline struct atsc_genre_descriptor* + atsc_genre_descriptor_codec(struct descriptor* d) +{ + struct atsc_genre_descriptor *ret = + (struct atsc_genre_descriptor *) d; + + if (d->len < 1) + return NULL; + + if (d->len != (1 + ret->attribute_count)) + return NULL; + + return (struct atsc_genre_descriptor*) d; +} + +/** + * Accessor for the attributes field of an atsc_genre_descriptor. + * + * @param d atsc_genre_descriptor pointer. + * @return Pointer to the attributes. + */ +static inline uint8_t* + atsc_genre_descriptor_attributes(struct atsc_genre_descriptor *d) +{ + return ((uint8_t*) d) + sizeof(struct atsc_genre_descriptor); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/mgt_section.c b/kaffeine/src/input/dvb/lib/libucsi/atsc/mgt_section.c new file mode 100644 index 0000000..bc6b3f2 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/mgt_section.c @@ -0,0 +1,76 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <libucsi/atsc/mgt_section.h> + +struct atsc_mgt_section *atsc_mgt_section_codec(struct atsc_section_psip *psip) +{ + uint8_t * buf = (uint8_t *) psip; + size_t pos = sizeof(struct atsc_section_psip); + size_t len = section_ext_length(&(psip->ext_head)); + struct atsc_mgt_section *mgt = (struct atsc_mgt_section *) psip; + int i; + + if (len < sizeof(struct atsc_mgt_section)) + return NULL; + + bswap16(buf + pos); + pos += 2; + + // we cannot use the tables_defined value here because of the braindead ATSC spec! + for(i=0; i < mgt->tables_defined; i++) { + // we think we're still in the tables - process as normal + if ((pos + sizeof(struct atsc_mgt_table)) > len) + return NULL; + struct atsc_mgt_table *table = (struct atsc_mgt_table *) (buf+pos); + + bswap16(buf+pos); + bswap16(buf+pos+2); + bswap32(buf+pos+5); + bswap16(buf+pos+9); + + pos += sizeof(struct atsc_mgt_table); + if ((pos + table->table_type_descriptors_length) > len) + return NULL; + if (verify_descriptors(buf + pos, table->table_type_descriptors_length)) + return NULL; + + pos += table->table_type_descriptors_length; + } + + if ((pos + sizeof(struct atsc_mgt_section_part2)) > len) + return NULL; + struct atsc_mgt_section_part2 *part2 = (struct atsc_mgt_section_part2 *) (buf+pos); + + bswap16(buf+pos); + + pos += sizeof(struct atsc_mgt_section_part2); + if ((pos + part2->descriptors_length) > len) + return NULL; + if (verify_descriptors(buf + pos, part2->descriptors_length)) + return NULL; + pos += part2->descriptors_length; + + if (pos != len) + return NULL; + + return (struct atsc_mgt_section *) psip; +} diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/mgt_section.h b/kaffeine/src/input/dvb/lib/libucsi/atsc/mgt_section.h new file mode 100644 index 0000000..3102a54 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/mgt_section.h @@ -0,0 +1,215 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_ATSC_MGT_SECTION_H +#define _UCSI_ATSC_MGT_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/atsc/section.h> + +enum atsc_mgt_section_table_type { + ATSC_MGT_TABLE_TYPE_TVCT_CURRENT = 0, + ATSC_MGT_TABLE_TYPE_TVCT_NEXT = 1, + ATSC_MGT_TABLE_TYPE_CVCT_CURRENT = 2, + ATSC_MGT_TABLE_TYPE_CVCT_NEXT = 3, + ATSC_MGT_TABLE_TYPE_CHANNEL_ETT = 4, + ATSC_MGT_TABLE_TYPE_DCCSCT = 5, +}; + +/** + * atsc_mgt_section structure. + */ +struct atsc_mgt_section { + struct atsc_section_psip head; + + uint16_t tables_defined; + /* struct atsc_mgt_table tables[] */ + /* struct atsc_mgt_section_part2 part2 */ +} __ucsi_packed; + +struct atsc_mgt_table { + uint16_t table_type; + EBIT2(uint16_t reserved : 3; , + uint16_t table_type_PID :13; ); + EBIT2(uint8_t reserved1 : 3; , + uint8_t table_type_version_number : 5; ); + uint32_t number_bytes; + EBIT2(uint16_t reserved2 : 4; , + uint16_t table_type_descriptors_length :12; ); + /* struct descriptor descriptors[] */ +} __ucsi_packed; + +struct atsc_mgt_section_part2 { + EBIT2(uint16_t reserved : 4; , + uint16_t descriptors_length :12; ); + /* struct descriptor descriptors[] */ +} __ucsi_packed; + +static inline struct atsc_mgt_table * atsc_mgt_section_tables_first(struct atsc_mgt_section *mgt); +static inline struct atsc_mgt_table * + atsc_mgt_section_tables_next(struct atsc_mgt_section *mgt, struct atsc_mgt_table *pos, int idx); + +/** + * Process a atsc_mgt_section. + * + * @param section Pointer to an atsc_section_psip structure. + * @return atsc_mgt_section pointer, or NULL on error. + */ +struct atsc_mgt_section *atsc_mgt_section_codec(struct atsc_section_psip *section); + +/** + * Iterator for the tables field in an atsc_mgt_section. + * + * @param mgt atsc_mgt_section pointer. + * @param pos Variable containing a pointer to the current atsc_mgt_table. + * @param idx Integer used to count which table we in. + */ +#define atsc_mgt_section_tables_for_each(mgt, pos, idx) \ + for ((pos) = atsc_mgt_section_tables_first(mgt), idx=0; \ + (pos); \ + (pos) = atsc_mgt_section_tables_next(mgt, pos, ++idx)) + +/** + * Iterator for the descriptors field in a atsc_mgt_table structure. + * + * @param table atsc_mgt_table pointer. + * @param pos Variable containing a pointer to the current descriptor. + */ +#define atsc_mgt_table_descriptors_for_each(table, pos) \ + for ((pos) = atsc_mgt_table_descriptors_first(table); \ + (pos); \ + (pos) = atsc_mgt_table_descriptors_next(table, pos)) + +/** + * Accessor for the second part of an atsc_mgt_section. + * + * @param mgt atsc_mgt_section pointer. + * @return atsc_mgt_section_part2 pointer. + */ +static inline struct atsc_mgt_section_part2 * + atsc_mgt_section_part2(struct atsc_mgt_section *mgt) +{ + int pos = sizeof(struct atsc_mgt_section); + + struct atsc_mgt_table *cur_table; + int idx; + atsc_mgt_section_tables_for_each(mgt, cur_table, idx) { + pos += sizeof(struct atsc_mgt_table); + pos += cur_table->table_type_descriptors_length; + } + + return (struct atsc_mgt_section_part2 *) (((uint8_t*) mgt) + pos); +} + +/** + * Iterator for the descriptors field in a atsc_mgt_section structure. + * + * @param part2 atsc_mgt_section_part2 pointer. + * @param pos Variable containing a pointer to the current descriptor. + */ +#define atsc_mgt_section_part2_descriptors_for_each(part2, pos) \ + for ((pos) = atsc_mgt_section_part2_descriptors_first(part2); \ + (pos); \ + (pos) = atsc_mgt_section_part2_descriptors_next(part2, pos)) + + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct atsc_mgt_table * + atsc_mgt_section_tables_first(struct atsc_mgt_section *mgt) +{ + size_t pos = sizeof(struct atsc_mgt_section); + + if (mgt->tables_defined == 0) + return NULL; + + return (struct atsc_mgt_table*) (((uint8_t *) mgt) + pos); +} + +static inline struct atsc_mgt_table * + atsc_mgt_section_tables_next(struct atsc_mgt_section *mgt, + struct atsc_mgt_table *pos, + int idx) +{ + if (idx >= mgt->tables_defined) + return NULL; + + return (struct atsc_mgt_table *) + (((uint8_t*) pos) + sizeof(struct atsc_mgt_table) + pos->table_type_descriptors_length); +} + +static inline struct descriptor * + atsc_mgt_table_descriptors_first(struct atsc_mgt_table *table) +{ + size_t pos = sizeof(struct atsc_mgt_table); + + if (table->table_type_descriptors_length == 0) + return NULL; + + return (struct descriptor*) (((uint8_t *) table) + pos); +} + +static inline struct descriptor * + atsc_mgt_table_descriptors_next(struct atsc_mgt_table *table, + struct descriptor *pos) +{ + return next_descriptor((uint8_t*) table + sizeof(struct atsc_mgt_table), + table->table_type_descriptors_length, + pos); +} + +static inline struct descriptor * + atsc_mgt_section_part2_descriptors_first(struct atsc_mgt_section_part2 *part2) +{ + size_t pos = sizeof(struct atsc_mgt_section_part2); + + if (part2->descriptors_length == 0) + return NULL; + + return (struct descriptor*) (((uint8_t *) part2) + pos); +} + +static inline struct descriptor * + atsc_mgt_section_part2_descriptors_next(struct atsc_mgt_section_part2 *part2, + struct descriptor *pos) +{ + return next_descriptor((uint8_t*) part2 + sizeof(struct atsc_mgt_section_part2), + part2->descriptors_length, + pos); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/rc_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/atsc/rc_descriptor.h new file mode 100644 index 0000000..4fb0e8e --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/rc_descriptor.h @@ -0,0 +1,83 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_ATSC_RC_DESCRIPTOR +#define _UCSI_ATSC_RC_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> + +/** + * atsc_rc_descriptor structure. + */ +struct atsc_rc_descriptor { + struct descriptor d; + + /* uint8_t info[] */ +} __ucsi_packed; + +/** + * Process an atsc_rc_descriptor. + * + * @param d Generic descriptor pointer. + * @return atsc_rc_descriptor pointer, or NULL on error. + */ +static inline struct atsc_rc_descriptor* + atsc_rc_descriptor_codec(struct descriptor* d) +{ + return (struct atsc_rc_descriptor*) d; +} + +/** + * Accessor for the info field of an atsc_rc_descriptor. + * + * @param d atsc_rc_descriptor pointer. + * @return Pointer to the atsc_text data. + */ +static inline uint8_t* + atsc_rc_descriptor_info(struct atsc_rc_descriptor *d) +{ + return ((uint8_t*) d) + sizeof(struct atsc_rc_descriptor); +} + +/** + * Accessor for the length of the info field of an atsc_rc_descriptor. + * + * @param d atsc_rc_descriptor pointer. + * @return The length + */ +static inline int + atsc_rc_descriptor_info_length(struct atsc_rc_descriptor *d) +{ + return d->d.len; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/rrt_section.c b/kaffeine/src/input/dvb/lib/libucsi/atsc/rrt_section.c new file mode 100644 index 0000000..6e96c3a --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/rrt_section.c @@ -0,0 +1,108 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <libucsi/atsc/rrt_section.h> + +struct atsc_rrt_section *atsc_rrt_section_codec(struct atsc_section_psip *psip) +{ + uint8_t * buf = (uint8_t *) psip; + size_t pos = 0; + size_t len = section_ext_length(&(psip->ext_head)); + int idx; + int vidx; + struct atsc_rrt_section *rrt = (struct atsc_rrt_section *) psip; + + if (len < sizeof(struct atsc_rrt_section)) + return NULL; + pos += sizeof(struct atsc_rrt_section); + + if (len < (pos + rrt->rating_region_name_length)) + return NULL; + if (atsc_text_validate(buf+pos, rrt->rating_region_name_length)) + return NULL; + + pos += rrt->rating_region_name_length; + if (len < (pos + sizeof(struct atsc_rrt_section_part2))) + return NULL; + struct atsc_rrt_section_part2 *rrtpart2 = (struct atsc_rrt_section_part2 *) (buf+pos); + + pos += sizeof(struct atsc_rrt_section_part2); + for(idx =0; idx < rrtpart2->dimensions_defined; idx++) { + if (len < (pos + sizeof(struct atsc_rrt_dimension))) + return NULL; + struct atsc_rrt_dimension *dimension = (struct atsc_rrt_dimension *) (buf+pos); + + pos += sizeof(struct atsc_rrt_dimension); + if (len < (pos + dimension->dimension_name_length)) + return NULL; + if (atsc_text_validate(buf+pos, dimension->dimension_name_length)) + return NULL; + + pos += dimension->dimension_name_length; + if (len < (pos + sizeof(struct atsc_rrt_dimension_part2))) + return NULL; + struct atsc_rrt_dimension_part2 *dpart2 = (struct atsc_rrt_dimension_part2 *) (buf+pos); + + pos += sizeof(struct atsc_rrt_dimension_part2); + for(vidx =0; vidx < dpart2->values_defined; vidx++) { + if (len < (pos + sizeof(struct atsc_rrt_dimension_value))) + return NULL; + struct atsc_rrt_dimension_value *value = (struct atsc_rrt_dimension_value *) (buf+pos); + + pos += sizeof(struct atsc_rrt_dimension_value); + if (len < (pos + value->abbrev_rating_value_length)) + return NULL; + if (atsc_text_validate(buf+pos, value->abbrev_rating_value_length)) + return NULL; + + pos += value->abbrev_rating_value_length; + if (len < (pos + sizeof(struct atsc_rrt_dimension_value_part2))) + return NULL; + struct atsc_rrt_dimension_value_part2 *vpart2 = + (struct atsc_rrt_dimension_value_part2 *) (buf+pos); + + pos += sizeof(struct atsc_rrt_dimension_value_part2); + if (len < (pos + vpart2->rating_value_length)) + return NULL; + if (atsc_text_validate(buf+pos, vpart2->rating_value_length)) + return NULL; + + pos+= vpart2->rating_value_length; + } + } + + if (len < (pos + sizeof(struct atsc_rrt_section_part3))) + return NULL; + struct atsc_rrt_section_part3 *part3 = (struct atsc_rrt_section_part3 *) (buf+pos); + + pos += sizeof(struct atsc_rrt_section_part3); + if (len < (pos + part3->descriptors_length)) + return NULL; + + if (verify_descriptors(buf + pos, part3->descriptors_length)) + return NULL; + + pos += part3->descriptors_length; + if (pos != len) + return NULL; + + return (struct atsc_rrt_section *) psip; +} diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/rrt_section.h b/kaffeine/src/input/dvb/lib/libucsi/atsc/rrt_section.h new file mode 100644 index 0000000..fba4596 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/rrt_section.h @@ -0,0 +1,379 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_ATSC_RRT_SECTION_H +#define _UCSI_ATSC_RRT_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/atsc/section.h> +#include <libucsi/atsc/types.h> + +/** + * atsc_rrt_section structure. + */ +struct atsc_rrt_section { + struct atsc_section_psip head; + + uint8_t rating_region_name_length; + /* struct atsc_text rating_region_name_text */ + /* struct atsc_rrt_section_part2 part2 */ +} __ucsi_packed; + +struct atsc_rrt_section_part2 { + uint8_t dimensions_defined; + /* struct atsc_rrt_dimension dimensions[] */ + /* struct atsc_rrt_section_part3 part3 */ +} __ucsi_packed; + +struct atsc_rrt_dimension { + uint8_t dimension_name_length; + /* struct atsc_text dimension_name_text */ + /* struct atsc_rrt_dimension_part2 part2 */ +} __ucsi_packed; + +struct atsc_rrt_dimension_part2 { + EBIT3(uint8_t reserved : 3; , + uint8_t graduated_scale : 1; , + uint8_t values_defined : 4; ); + /* struct atsc_rrt_dimension_value values[] */ +} __ucsi_packed; + +struct atsc_rrt_dimension_value { + uint8_t abbrev_rating_value_length; + /* struct atsc_text abbrev_rating_value_text */ + /* struct atsc_rrt_dimension_value_part2 */ +} __ucsi_packed; + +struct atsc_rrt_dimension_value_part2 { + uint8_t rating_value_length; + /* struct atsc_text rating_value_text */ +} __ucsi_packed; + +struct atsc_rrt_section_part3 { + EBIT2(uint16_t reserved : 6; , + uint16_t descriptors_length :10; ); + /* struct descriptor descriptors[] */ +} __ucsi_packed; + + +static inline struct atsc_rrt_dimension * + atsc_rrt_section_dimensions_first(struct atsc_rrt_section_part2 *part2); +static inline struct atsc_rrt_dimension * + atsc_rrt_section_dimensions_next(struct atsc_rrt_section_part2 *part2, + struct atsc_rrt_dimension *pos, + int idx); +static inline struct atsc_rrt_dimension_value * + atsc_rrt_dimension_part2_values_first(struct atsc_rrt_dimension_part2 *part2); +static inline struct atsc_rrt_dimension_value * + atsc_rrt_dimension_part2_values_next(struct atsc_rrt_dimension_part2 *part2, + struct atsc_rrt_dimension_value *pos, + int idx); + +/** + * Process a atsc_rrt_section. + * + * @param section Pointer to anj atsc_section_psip structure. + * @return atsc_rrt_section pointer, or NULL on error. + */ +struct atsc_rrt_section *atsc_rrt_section_codec(struct atsc_section_psip *section); + +/** + * Accessor for the rating_region field of an RRT. + * + * @param rrt RRT pointer. + * @return The transport_stream_id. + */ +static inline uint8_t atsc_rrt_section_rating_region(struct atsc_rrt_section *rrt) +{ + return rrt->head.ext_head.table_id_ext & 0xff; +} + +/** + * Accessor for the rating_region_name_text field of an RRT. + * + * @param rrt RRT pointer. + * @return struct atsc_text pointer, or NULL. + */ +static inline struct atsc_text *atsc_rrt_section_rating_region_name_text(struct atsc_rrt_section *rrt) +{ + if (rrt->rating_region_name_length == 0) + return NULL; + + return (struct atsc_text*)(((uint8_t*) rrt) + sizeof(struct atsc_rrt_section)); +} + +/** + * Accessor for the part2 field of an RRT. + * + * @param rrt RRT pointer. + * @return struct atsc_rrt_section_part2 pointer. + */ +static inline struct atsc_rrt_section_part2 *atsc_rrt_section_part2(struct atsc_rrt_section *rrt) +{ + return (struct atsc_rrt_section_part2 *) + (((uint8_t*) rrt) + sizeof(struct atsc_rrt_section) + + rrt->rating_region_name_length); +} + +/** + * Iterator for the dimensions field in an atsc_rrt_section_part2. + * + * @param rrt atsc_rrt_section pointer. + * @param pos Variable containing a pointer to the current atsc_rrt_dimension. + * @param idx Integer used to count which dimension we are in. + */ +#define atsc_rrt_section_dimensions_for_each(rrt, pos, idx) \ + for ((pos) = atsc_rrt_section_dimensions_first(rrt), idx=0; \ + (pos); \ + (pos) = atsc_rrt_section_dimensions_next(rrt, pos, ++idx)) + +/** + * Accessor for the dimension_name_text field of an atsc_rrt_dimension. + * + * @param dimension atsc_rrt_dimension pointer. + * @return struct atsc_text pointer, or NULL on error. + */ +static inline struct atsc_text *atsc_rrt_dimension_name_text(struct atsc_rrt_dimension *dimension) +{ + if (dimension->dimension_name_length == 0) + return NULL; + + return (struct atsc_text*)(((uint8_t*) dimension) + sizeof(struct atsc_rrt_dimension)); +} + +/** + * Accessor for the part2 field of an atsc_rrt_dimension. + * + * @param dimension atsc_rrt_dimension pointer. + * @return struct atsc_rrt_dimension_part2 pointer. + */ +static inline struct atsc_rrt_dimension_part2 *atsc_rrt_dimension_part2(struct atsc_rrt_dimension *dimension) +{ + return (struct atsc_rrt_dimension_part2 *) + (((uint8_t*) dimension) + + sizeof(struct atsc_rrt_dimension) + + dimension->dimension_name_length); +} + +/** + * Iterator for the values field in a atsc_rrt_dimension_part2 structure. + * + * @param part2 atsc_rrt_dimension_part2 pointer. + * @param pos Variable containing a pointer to the current value. + * @param idx Integer used to count which value we are in + */ +#define atsc_rrt_dimension_part2_values_for_each(part2, pos, idx) \ + for ((pos) = atsc_rrt_dimension_part2_values_first(part2), idx=0; \ + (pos); \ + (pos) = atsc_rrt_dimension_part2_values_next(part2, pos, ++idx)) + +/** + * Accessor for the dimension_name_text field of an atsc_rrt_dimension. + * + * @param dimension atsc_rrt_dimension pointer. + * @return struct atsc_text pointer. + */ +static inline struct atsc_text * + atsc_rrt_dimension_value_abbrev_rating_value_text(struct atsc_rrt_dimension_value *value) +{ + if (value->abbrev_rating_value_length == 0) + return NULL; + + return (struct atsc_text*)(((uint8_t*) value) + sizeof(struct atsc_rrt_dimension_value)); +} + +/** + * Accessor for the part2 field of an atsc_rrt_dimension_value. + * + * @param value atsc_rrt_dimension_value pointer. + * @return struct atsc_rrt_dimension_value_part2 pointer. + */ +static inline struct atsc_rrt_dimension_value_part2 *atsc_rrt_dimension_value_part2(struct atsc_rrt_dimension_value *value) +{ + return (struct atsc_rrt_dimension_value_part2 *) + (((uint8_t*) value) + + sizeof(struct atsc_rrt_dimension_value) + + value->abbrev_rating_value_length); +} + +/** + * Accessor for the rating_value_text field of an atsc_rrt_dimension_value_part2. + * + * @param part2 atsc_rrt_dimension_value_part2 pointer. + * @return struct atsc_text pointer. + */ +static inline struct atsc_text *atsc_rrt_dimension_value_part2_rating_value_text(struct atsc_rrt_dimension_value_part2 *part2) +{ + if (part2->rating_value_length == 0) + return NULL; + + return (struct atsc_text*)(((uint8_t*) part2) + sizeof(struct atsc_rrt_dimension_value_part2)); +} + +/** + * Accessor for the third part of an atsc_rrt_section. + * + * @param part2 atsc_rrt_section_part2 pointer. + * @return atsc_rrt_section_part3 pointer. + */ +static inline struct atsc_rrt_section_part3 * + atsc_rrt_section_part3(struct atsc_rrt_section_part2 *part2) +{ + int pos = sizeof(struct atsc_rrt_section_part2); + + struct atsc_rrt_dimension *cur_dimension; + int idx; + atsc_rrt_section_dimensions_for_each(part2, cur_dimension, idx) { + pos += sizeof(struct atsc_rrt_dimension); + pos += cur_dimension->dimension_name_length; + pos += sizeof(struct atsc_rrt_dimension_part2); + + // now we need to iterate over the values. yuck + struct atsc_rrt_dimension_part2 *dpart2 = atsc_rrt_dimension_part2(cur_dimension); + struct atsc_rrt_dimension_value *cur_value; + int vidx; + atsc_rrt_dimension_part2_values_for_each(dpart2, cur_value, vidx) { + pos += sizeof(struct atsc_rrt_dimension_value); + pos += cur_value->abbrev_rating_value_length; + + struct atsc_rrt_dimension_value_part2 *vpart2 = atsc_rrt_dimension_value_part2(cur_value); + pos += sizeof(struct atsc_rrt_dimension_value_part2); + pos += vpart2->rating_value_length; + } + } + + return (struct atsc_rrt_section_part3 *) (((uint8_t*) part2) + pos); +} + +/** + * Iterator for the descriptors field in a atsc_rrt_section structure. + * + * @param part3 atsc_rrt_section_part3 pointer. + * @param pos Variable containing a pointer to the current descriptor. + */ +#define atsc_rrt_section_part3_descriptors_for_each(part3, pos) \ + for ((pos) = atsc_rrt_section_part3_descriptors_first(part3); \ + (pos); \ + (pos) = atsc_rrt_section_part3_descriptors_next(part3, pos)) + + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct atsc_rrt_dimension * + atsc_rrt_section_dimensions_first(struct atsc_rrt_section_part2 *part2) +{ + size_t pos = sizeof(struct atsc_rrt_section_part2); + + if (part2->dimensions_defined == 0) + return NULL; + + return (struct atsc_rrt_dimension*) (((uint8_t *) part2) + pos); +} + +static inline struct atsc_rrt_dimension * + atsc_rrt_section_dimensions_next(struct atsc_rrt_section_part2 *part2, + struct atsc_rrt_dimension *pos, + int idx) +{ + if (idx >= part2->dimensions_defined) + return NULL; + + struct atsc_rrt_dimension_part2 *dpart2 = atsc_rrt_dimension_part2(pos); + int len = sizeof(struct atsc_rrt_dimension_part2); + + // now we need to iterate over the values. yuck + struct atsc_rrt_dimension_value *cur_value; + int vidx; + atsc_rrt_dimension_part2_values_for_each(dpart2, cur_value, vidx) { + len += sizeof(struct atsc_rrt_dimension_value); + len += cur_value->abbrev_rating_value_length; + + struct atsc_rrt_dimension_value_part2 *vpart2 = atsc_rrt_dimension_value_part2(cur_value); + len += sizeof(struct atsc_rrt_dimension_value_part2); + len += vpart2->rating_value_length; + } + + return (struct atsc_rrt_dimension *) (((uint8_t*) dpart2) + len); +} + +static inline struct atsc_rrt_dimension_value * + atsc_rrt_dimension_part2_values_first(struct atsc_rrt_dimension_part2 *part2) +{ + size_t pos = sizeof(struct atsc_rrt_dimension_part2); + + if (part2->values_defined == 0) + return NULL; + + return (struct atsc_rrt_dimension_value*) (((uint8_t *) part2) + pos); +} + +static inline struct atsc_rrt_dimension_value * + atsc_rrt_dimension_part2_values_next(struct atsc_rrt_dimension_part2 *part2, + struct atsc_rrt_dimension_value *pos, + int idx) +{ + if (idx >= part2->values_defined) + return NULL; + + struct atsc_rrt_dimension_value_part2 *vpart2 = atsc_rrt_dimension_value_part2(pos); + int len = sizeof(struct atsc_rrt_dimension_value_part2); + len += vpart2->rating_value_length; + + return (struct atsc_rrt_dimension_value *) (((uint8_t*) vpart2) + len); +} + +static inline struct descriptor * + atsc_rrt_section_part3_descriptors_first(struct atsc_rrt_section_part3 *part3) +{ + size_t pos = sizeof(struct atsc_rrt_section_part3); + + if (part3->descriptors_length == 0) + return NULL; + + return (struct descriptor*) (((uint8_t *) part3) + pos); +} + +static inline struct descriptor * + atsc_rrt_section_part3_descriptors_next(struct atsc_rrt_section_part3 *part3, + struct descriptor *pos) +{ + return next_descriptor((uint8_t*) part3 + sizeof(struct atsc_rrt_section_part3), + part3->descriptors_length, + pos); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/section.h b/kaffeine/src/input/dvb/lib/libucsi/atsc/section.h index e693b9d..23d59ea 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/atsc/section.h +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/section.h @@ -19,6 +19,17 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ +#include <libucsi/section.h> +#include <libucsi/atsc/mgt_section.h> +#include <libucsi/atsc/tvct_section.h> +#include <libucsi/atsc/cvct_section.h> +#include <libucsi/atsc/rrt_section.h> +#include <libucsi/atsc/eit_section.h> +#include <libucsi/atsc/ett_section.h> +#include <libucsi/atsc/stt_section.h> +#include <libucsi/atsc/dcct_section.h> +#include <libucsi/atsc/dccsct_section.h> + #ifndef _UCSI_ATSC_SECTION_H #define _UCSI_ATSC_SECTION_H 1 @@ -27,40 +38,44 @@ extern "C" { #endif +#define ATSC_BASE_PID 0x1ffb + /** * Enumeration of ATSC section tags. */ enum atsc_section_tag { -/* 0xC0-0xC6 [ATSC coordinated values which are defined in other standards.] */ - stag_atsc_master_guide = 0xc7, + stag_atsc_master_guide = 0xc7, stag_atsc_terrestrial_virtual_channel = 0xc8, - stag_atsc_cable_virtual_channel = 0xc9, - stag_atsc_rating_region = 0xca, - stag_atsc_event_informationen = 0xcb, - stag_atsc_extended_text = 0xcc, + stag_atsc_cable_virtual_channel = 0xc9, + stag_atsc_rating_region = 0xca, + stag_atsc_event_information = 0xcb, + stag_atsc_extended_text = 0xcc, stag_atsc_system_time = 0xcd, +}; - stag_atsc_data_event = 0xce, - stag_atsc_data_service = 0xcf, - stag_atsc_network_resources = 0xd1, - stag_atsc_long_term_serivce = 0xd2, -/* identical to DVB/ISO ? - 0x3F DSM-CC Addressable Section Table - 0x3B DSM-CC Section Table - 0x3C DSM-CC Section Table */ - - /* 0xCE-0xD2 [ATSC coordinated values which are defined in other standards.] */ - stag_atsc_directed_channel_change = 0xd3, - stag_atsc_directed_channel_change_selection_code = 0xd4, +/** + * ATSC specific PSIP section structure. + */ +struct atsc_section_psip { + struct section_ext ext_head; + uint8_t protocol_version; +} __ucsi_packed; - /* 0xD5-0xDF [ATSC coordinated values which are defined in other standards.] */ - stag_atsc_aggregate_event_information = 0xd6, - stag_atsc_aggregate_extended_text = 0xd7, - stag_atsc_satellite_virtual_channel = 0xda, +/** + * Decode a PSIP section structure. + * + * @param section_ext Pointer to the processed section_ext structure. + * @return Pointer to the parsed section_psip structure, or NULL if invalid. + */ +static inline struct atsc_section_psip *atsc_section_psip_decode(struct section_ext *section_ext) +{ + size_t len = section_ext_length(section_ext); + if (len < sizeof(struct atsc_section_psip)) { + return NULL; + } - /* 0xE0-0xE5 [Used in other systems] */ - /* 0xE6-0xFE [Reserved for future ATSC use] */ -}; + return (struct atsc_section_psip *) section_ext; +} #ifdef __cplusplus } diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/service_location_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/atsc/service_location_descriptor.h new file mode 100644 index 0000000..aad5b4a --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/service_location_descriptor.h @@ -0,0 +1,141 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_ATSC_SERVICE_LOCATION_DESCRIPTOR +#define _UCSI_ATSC_SERVICE_LOCATION_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> + +enum atsc_stream_types { + ATSC_STREAM_TYPE_VIDEO = 0x02, + ATSC_STREAM_TYPE_AUDIO = 0x81, +}; + +/** + * atsc_service_location_descriptor structure. + */ +struct atsc_service_location_descriptor { + struct descriptor d; + + EBIT2(uint16_t reserved : 3; , + uint16_t PCR_PID :13; ); + uint8_t number_elements; + /* struct atsc_service_location_element elements[] */ +} __ucsi_packed; + +/** + * An entry in the elements field of an atsc_service_location_descriptor. + */ +struct atsc_caption_service_location_element { + uint8_t stream_type; + EBIT2(uint16_t reserved : 3; , + uint16_t elementary_PID :13; ); + iso639lang_t language_code; +} __ucsi_packed; + +/** + * Process an atsc_service_location_descriptor. + * + * @param d Generic descriptor pointer. + * @return atsc_service_location_descriptor pointer, or NULL on error. + */ +static inline struct atsc_service_location_descriptor* + atsc_service_location_descriptor_codec(struct descriptor* d) +{ + struct atsc_service_location_descriptor *ret = + (struct atsc_service_location_descriptor *) d; + uint8_t *buf = (uint8_t*) d + 2; + int pos = 0; + int idx; + + if (d->len < 3) + return NULL; + bswap16(buf + pos); + pos+=3; + + for(idx = 0; idx < ret->number_elements; idx++) { + if (d->len < (pos + sizeof(struct atsc_caption_service_entry))) + return NULL; + + bswap16(buf+pos+1); + + pos += sizeof(struct atsc_caption_service_entry); + } + + return (struct atsc_service_location_descriptor*) d; +} + +/** + * Iterator for elements field of a atsc_service_location_descriptor. + * + * @param d atsc_service_location_descriptor pointer. + * @param pos Variable holding a pointer to the current atsc_service_location_element. + * @param idx Integer used to count which dimension we are in. + */ +#define atsc_service_location_descriptor_elements_for_each(d, pos, idx) \ + for ((pos) = atsc_service_location_descriptor_elements_first(d), idx=0; \ + (pos); \ + (pos) = atsc_service_location_descriptor_elements_next(d, pos, ++idx)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct atsc_caption_service_location_element* + atsc_service_location_descriptor_elements_first(struct atsc_service_location_descriptor *d) +{ + if (d->number_elements == 0) + return NULL; + + return (struct atsc_caption_service_location_element *) + ((uint8_t*) d + sizeof(struct atsc_service_location_descriptor)); +} + +static inline struct atsc_caption_service_location_element* + atsc_service_location_descriptor_elements_next(struct atsc_service_location_descriptor *d, + struct atsc_caption_service_location_element *pos, + int idx) +{ + uint8_t *next = (uint8_t *) pos + sizeof(struct atsc_caption_service_location_element); + + if (idx >= d->number_elements) + return NULL; + return (struct atsc_caption_service_location_element *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/stt_section.c b/kaffeine/src/input/dvb/lib/libucsi/atsc/stt_section.c new file mode 100644 index 0000000..23ddd76 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/stt_section.c @@ -0,0 +1,42 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <libucsi/atsc/stt_section.h> + +struct atsc_stt_section *atsc_stt_section_codec(struct atsc_section_psip *psip) +{ + uint8_t *buf = (uint8_t *) psip; + size_t pos = sizeof(struct atsc_section_psip); + size_t len = section_ext_length(&(psip->ext_head)); + + if (len < sizeof(struct atsc_stt_section)) + return NULL; + + bswap32(buf + pos); + pos += 5; + bswap16(buf + pos); + pos += 2; + + if (verify_descriptors(buf + pos, len - sizeof(struct atsc_stt_section))) + return NULL; + + return (struct atsc_stt_section *) psip; +} diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/stt_section.h b/kaffeine/src/input/dvb/lib/libucsi/atsc/stt_section.h new file mode 100644 index 0000000..79db5a1 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/stt_section.h @@ -0,0 +1,105 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_ATSC_STT_SECTION_H +#define _UCSI_ATSC_STT_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/atsc/section.h> +#include <libucsi/atsc/types.h> + +/** + * atsc_stt_section structure. + */ +struct atsc_stt_section { + struct atsc_section_psip head; + + atsctime_t system_time; + uint8_t gps_utc_offset; + EBIT4(uint16_t DS_status : 1; , + uint16_t reserved : 2; , + uint16_t DS_day_of_month : 5; , + uint16_t DS_hour : 8; ); + /* struct descriptor descriptors[] */ +} __ucsi_packed; + +/** + * Process a atsc_stt_section. + * + * @param section Pointer to an atsc_section_psip structure. + * @return atsc_stt_section pointer, or NULL on error. + */ +struct atsc_stt_section *atsc_stt_section_codec(struct atsc_section_psip *section); + +/** + * Iterator for the services field in a atsc_stt_section. + * + * @param stt atsc_stt_section pointer. + * @param pos Variable containing a pointer to the current descriptor. + */ +#define atsc_stt_section_descriptors_for_each(stt, pos) \ + for ((pos) = atsc_stt_section_descriptors_first(stt); \ + (pos); \ + (pos) = atsc_stt_section_descriptors_next(stt, pos)) + + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct descriptor * + atsc_stt_section_descriptors_first(struct atsc_stt_section *stt) +{ + size_t pos = sizeof(struct atsc_stt_section); + + if (pos >= section_ext_length(&stt->head.ext_head)) + return NULL; + + return (struct descriptor*) ((uint8_t *) stt + pos); +} + +static inline struct descriptor * + atsc_stt_section_descriptors_next(struct atsc_stt_section *stt, + struct descriptor *pos) +{ + int len = section_ext_length(&stt->head.ext_head); + len -= sizeof(struct atsc_stt_section); + + return next_descriptor((uint8_t*) stt + sizeof(struct atsc_stt_section), + len, + pos); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/stuffing_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/atsc/stuffing_descriptor.h new file mode 100644 index 0000000..777c282 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/stuffing_descriptor.h @@ -0,0 +1,82 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_atsc@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_ATSC_STUFFING_DESCRIPTOR +#define _UCSI_ATSC_STUFFING_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> + +/** + * atsc_stuffing_descriptor. + */ +struct atsc_stuffing_descriptor { + struct descriptor d; + + /* uint8_t data[] */ +} __ucsi_packed; + +/** + * Process a atsc_stuffing_descriptor. + * + * @param d Generic descriptor structure. + * @return atsc_stuffing_descriptor pointer, or NULL on error. + */ +static inline struct atsc_stuffing_descriptor* + atsc_stuffing_descriptor_codec(struct descriptor* d) +{ + return (struct atsc_stuffing_descriptor*) d; +} + +/** + * Retrieve a pointer to the data field of a atsc_stuffing_descriptor. + * + * @param d atsc_stuffing_descriptor pointer. + * @return Pointer to the field. + */ +static inline uint8_t * + atsc_stuffing_descriptor_data(struct atsc_stuffing_descriptor *d) +{ + return (uint8_t *) d + sizeof(struct atsc_stuffing_descriptor); +} + +/** + * Calculate length of the data field of a atsc_stuffing_descriptor. + * + * @param d atsc_stuffing_descriptor pointer. + * @return The length in bytes. + */ +static inline int + atsc_stuffing_descriptor_data_length(struct atsc_stuffing_descriptor *d) +{ + return d->d.len; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/time_shifted_service_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/atsc/time_shifted_service_descriptor.h new file mode 100644 index 0000000..599e66d --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/time_shifted_service_descriptor.h @@ -0,0 +1,136 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_ATSC_TIME_SHIFTED_SERVICE_DESCRIPTOR +#define _UCSI_ATSC_TIME_SHIFTED_SERVICE_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/endianops.h> +#include <libucsi/types.h> + +/** + * atsc_time_shifted_service_descriptor structure. + */ +struct atsc_time_shifted_service_descriptor { + struct descriptor d; + + EBIT2(uint8_t reserved : 3; , + uint8_t number_of_services : 5; ); + /* struct atsc_time_shifted_service services[] */ +} __ucsi_packed; + +/** + * An entry in the services field of an atsc_time_shifted_service_descriptor. + */ +struct atsc_time_shifted_service { + EBIT2(uint16_t reserved : 6; , + uint16_t time_shift :10; ); + EBIT3(uint32_t reserved2 : 4; , + uint32_t major_channel_number :10; , + uint32_t minor_channel_number :10; ); +} __ucsi_packed; + +/** + * Process an atsc_time_shifted_service_descriptor. + * + * @param d Generic descriptor pointer. + * @return atsc_time_shifted_service_descriptor pointer, or NULL on error. + */ +static inline struct atsc_time_shifted_service_descriptor* + atsc_time_shifted_service_descriptor_codec(struct descriptor* d) +{ + struct atsc_time_shifted_service_descriptor *ret = + (struct atsc_time_shifted_service_descriptor *) d; + uint8_t *buf = (uint8_t*) d + 2; + int pos = 0; + int idx; + + if (d->len < 1) + return NULL; + pos++; + + for(idx = 0; idx < ret->number_of_services; idx++) { + if (d->len < (pos + sizeof(struct atsc_time_shifted_service))) + return NULL; + + bswap16(buf+pos); + bswap24(buf+pos+2); + + pos += sizeof(struct atsc_time_shifted_service); + } + + return (struct atsc_time_shifted_service_descriptor*) d; +} + +/** + * Iterator for services field of a atsc_time_shifted_service_descriptor. + * + * @param d atsc_time_shifted_service_descriptor pointer. + * @param pos Variable holding a pointer to the current atsc_service_location_element. + * @param idx Integer used to count which service we are in. + */ +#define atsc_time_shifted_service_descriptor_services_for_each(d, pos, idx) \ + for ((pos) = atsc_time_shifted_service_descriptor_services_first(d), idx=0; \ + (pos); \ + (pos) = atsc_time_shifted_service_descriptor_services_next(d, pos, ++idx)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct atsc_time_shifted_service* + atsc_time_shifted_service_descriptor_services_first(struct atsc_time_shifted_service_descriptor *d) +{ + if (d->number_of_services == 0) + return NULL; + + return (struct atsc_time_shifted_service *) + ((uint8_t*) d + sizeof(struct atsc_time_shifted_service_descriptor)); +} + +static inline struct atsc_time_shifted_service* + atsc_time_shifted_service_descriptor_services_next(struct atsc_time_shifted_service_descriptor *d, + struct atsc_time_shifted_service *pos, + int idx) +{ + uint8_t *next = (uint8_t *) pos + sizeof(struct atsc_time_shifted_service); + + if (idx >= d->number_of_services) + return NULL; + return (struct atsc_time_shifted_service *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/tvct_section.c b/kaffeine/src/input/dvb/lib/libucsi/atsc/tvct_section.c new file mode 100644 index 0000000..d187414 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/tvct_section.c @@ -0,0 +1,81 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <libucsi/atsc/tvct_section.h> + +struct atsc_tvct_section *atsc_tvct_section_codec(struct atsc_section_psip *psip) +{ + uint8_t * buf = (uint8_t *) psip; + size_t pos = sizeof(struct atsc_section_psip); + size_t len = section_ext_length(&(psip->ext_head)); + int idx; + struct atsc_tvct_section *tvct = (struct atsc_tvct_section *) psip; + + if (len < sizeof(struct atsc_tvct_section)) + return NULL; + + pos++; + + for(idx =0; idx < tvct->num_channels_in_section; idx++) { + + if ((pos + sizeof(struct atsc_tvct_channel)) > len) + return NULL; + struct atsc_tvct_channel *channel = (struct atsc_tvct_channel *) (buf+pos); + + pos += 7*2; + + bswap32(buf+pos); + bswap32(buf+pos+4); + bswap16(buf+pos+8); + bswap16(buf+pos+10); + bswap16(buf+pos+12); + bswap16(buf+pos+14); + bswap16(buf+pos+16); + pos+=18; + + if ((pos + channel->descriptors_length) > len) + return NULL; + if (verify_descriptors(buf + pos, channel->descriptors_length)) + return NULL; + + pos += channel->descriptors_length; + } + + if ((pos + sizeof(struct atsc_tvct_section_part2)) > len) + return NULL; + struct atsc_tvct_section_part2 *part2 = (struct atsc_tvct_section_part2 *) (buf+pos); + + bswap16(buf+pos); + pos+=2; + + if ((pos + part2->descriptors_length) > len) + return NULL; + + if (verify_descriptors(buf + pos, part2->descriptors_length)) + return NULL; + + pos += part2->descriptors_length; + + if (pos != len) + return NULL; + + return (struct atsc_tvct_section *) psip; +} diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/tvct_section.h b/kaffeine/src/input/dvb/lib/libucsi/atsc/tvct_section.h new file mode 100644 index 0000000..77bc5f4 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/tvct_section.h @@ -0,0 +1,227 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_ATSC_TVCT_SECTION_H +#define _UCSI_ATSC_TVCT_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/atsc/section.h> + +/** + * atsc_tvct_section structure. + */ +struct atsc_tvct_section { + struct atsc_section_psip head; + + uint8_t num_channels_in_section; + /* struct atsc_tvct_channel channels[] */ + /* struct atsc_tvct_channel_part2 part2 */ +} __ucsi_packed; + +struct atsc_tvct_channel { + uint16_t short_name[7]; // UTF-16 network ordered + EBIT4(uint32_t reserved : 4; , + uint32_t major_channel_number :10; , + uint32_t minor_channel_number :10; , + uint32_t modulation_mode : 8; ); + uint32_t carrier_frequency; + uint16_t channel_TSID; + uint16_t program_number; + EBIT7(uint16_t ETM_location : 2; , + uint16_t access_controlled : 1; , + uint16_t hidden : 1; , + uint16_t reserved1 : 2; , + uint16_t hide_guide : 1; , + uint16_t reserved2 : 3; , + uint16_t service_type : 6; ); + uint16_t source_id; + EBIT2(uint16_t reserved3 : 6; , + uint16_t descriptors_length :10; ); + /* struct descriptor descriptors[] */ +} __ucsi_packed; + +struct atsc_tvct_section_part2 { + EBIT2(uint16_t reserved : 6; , + uint16_t descriptors_length :10; ); + /* struct descriptor descriptors[] */ +} __ucsi_packed; + +static inline struct atsc_tvct_channel *atsc_tvct_section_channels_first(struct atsc_tvct_section *tvct); +static inline struct atsc_tvct_channel * + atsc_tvct_section_channels_next(struct atsc_tvct_section *tvct, struct atsc_tvct_channel *pos, int idx); + +/** + * Process a atsc_tvct_section. + * + * @param section Pointer to an atsc_section_psip structure. + * @return atsc_tvct_section pointer, or NULL on error. + */ +struct atsc_tvct_section *atsc_tvct_section_codec(struct atsc_section_psip *section); + +/** + * Accessor for the transport_stream_id field of a TVCT. + * + * @param tvct TVCT pointer. + * @return The transport_stream_id. + */ +static inline uint16_t atsc_tvct_section_transport_stream_id(struct atsc_tvct_section *tvct) +{ + return tvct->head.ext_head.table_id_ext; +} + +/** + * Iterator for the channels field in an atsc_tvct_section. + * + * @param mgt atsc_tvct_section pointer. + * @param pos Variable containing a pointer to the current atsc_tvct_channel. + * @param idx Integer used to count which channel we in. + */ +#define atsc_tvct_section_channels_for_each(mgt, pos, idx) \ + for ((pos) = atsc_tvct_section_channels_first(mgt), idx=0; \ + (pos); \ + (pos) = atsc_tvct_section_channels_next(mgt, pos, ++idx)) + +/** + * Iterator for the descriptors field in a atsc_tvct_channel structure. + * + * @param channel atsc_tvct_channel pointer. + * @param pos Variable containing a pointer to the current descriptor. + */ +#define atsc_tvct_channel_descriptors_for_each(channel, pos) \ + for ((pos) = atsc_tvct_channel_descriptors_first(channel); \ + (pos); \ + (pos) = atsc_tvct_channel_descriptors_next(channel, pos)) + +/** + * Accessor for the second part of an atsc_tvct_section. + * + * @param mgt atsc_tvct_section pointer. + * @return atsc_tvct_section_part2 pointer. + */ +static inline struct atsc_tvct_section_part2 * + atsc_tvct_section_part2(struct atsc_tvct_section *mgt) +{ + int pos = sizeof(struct atsc_tvct_section); + + struct atsc_tvct_channel *cur_channel; + int idx; + atsc_tvct_section_channels_for_each(mgt, cur_channel, idx) { + pos += sizeof(struct atsc_tvct_channel); + pos += cur_channel->descriptors_length; + } + + return (struct atsc_tvct_section_part2 *) (((uint8_t*) mgt) + pos); +} + +/** + * Iterator for the descriptors field in a atsc_tvct_section structure. + * + * @param part2 atsc_tvct_section_part2 pointer. + * @param pos Variable containing a pointer to the current descriptor. + */ +#define atsc_tvct_section_part2_descriptors_for_each(part2, pos) \ + for ((pos) = atsc_tvct_section_part2_descriptors_first(part2); \ + (pos); \ + (pos) = atsc_tvct_section_part2_descriptors_next(part2, pos)) + + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct atsc_tvct_channel * + atsc_tvct_section_channels_first(struct atsc_tvct_section *tvct) +{ + size_t pos = sizeof(struct atsc_tvct_section); + + if (tvct->num_channels_in_section == 0) + return NULL; + + return (struct atsc_tvct_channel*) (((uint8_t *) tvct) + pos); +} + +static inline struct atsc_tvct_channel * + atsc_tvct_section_channels_next(struct atsc_tvct_section *tvct, + struct atsc_tvct_channel *pos, + int idx) +{ + if (idx >= tvct->num_channels_in_section) + return NULL; + + return (struct atsc_tvct_channel *) + (((uint8_t*) pos) + sizeof(struct atsc_tvct_channel) + pos->descriptors_length); +} + +static inline struct descriptor * + atsc_tvct_channel_descriptors_first(struct atsc_tvct_channel *channel) +{ + size_t pos = sizeof(struct atsc_tvct_channel); + + if (channel->descriptors_length == 0) + return NULL; + + return (struct descriptor*) (((uint8_t *) channel) + pos); +} + +static inline struct descriptor * + atsc_tvct_channel_descriptors_next(struct atsc_tvct_channel *channel, + struct descriptor *pos) +{ + return next_descriptor((uint8_t*) channel + sizeof(struct atsc_tvct_channel), + channel->descriptors_length, + pos); +} + +static inline struct descriptor * + atsc_tvct_section_part2_descriptors_first(struct atsc_tvct_section_part2 *part2) +{ + size_t pos = sizeof(struct atsc_tvct_section_part2); + + if (part2->descriptors_length == 0) + return NULL; + + return (struct descriptor*) (((uint8_t *) part2) + pos); +} + +static inline struct descriptor * + atsc_tvct_section_part2_descriptors_next(struct atsc_tvct_section_part2 *part2, + struct descriptor *pos) +{ + return next_descriptor((uint8_t*) part2 + sizeof(struct atsc_tvct_section_part2), + part2->descriptors_length, + pos); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/types.c b/kaffeine/src/input/dvb/lib/libucsi/atsc/types.c new file mode 100644 index 0000000..8f4b7ea --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/types.c @@ -0,0 +1,71 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <string.h> +#include "libucsi/atsc/types.h" + +/* GPS epoch == unix time_t at 06/Jan/1980 */ +#define GPS_EPOCH 315964800 + + +int atsc_text_validate(uint8_t *buf, int len) +{ + int i; + int j; + int number_strings; + int number_segments; + int number_bytes; + int pos = 0; + + if (len == 0) + return 0; + number_strings = buf[pos]; + pos++; + + for(i=0; i< number_strings; i++) { + if (len < (pos+4)) + return -1; + number_segments = buf[pos+3]; + pos+=4; + + for(j=0; j < number_segments; j++) { + if (len < (pos+3)) + return -1; + number_bytes = buf[pos+2]; + pos+=3; + + if (len < (pos + number_bytes)) + return -1; + pos += number_bytes; + } + } + + return 0; +} + +time_t atsctime_to_unixtime(atsctime_t atsc) +{ + return atsc + GPS_EPOCH; +} + +atsctime_t unixtime_to_atsctime(time_t t) +{ + return t - GPS_EPOCH; +} diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/types.h b/kaffeine/src/input/dvb/lib/libucsi/atsc/types.h new file mode 100644 index 0000000..4d4b802 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/types.h @@ -0,0 +1,227 @@ + /* + * section and descriptor parser + * + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_ATSC_TYPES_H +#define _UCSI_ATSC_TYPES_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdint.h> +#include <time.h> +#include <libucsi/types.h> + +enum atsc_vct_modulation { + ATSC_VCT_MODULATION_ANALOG = 0x01, + ATSC_VCT_MODULATION_SCTE_MODE1 = 0x02, + ATSC_VCT_MODULATION_SCTE_MODE2 = 0x03, + ATSC_VCT_MODULATION_8VSB = 0x04, + ATSC_VCT_MODULATION_16VSB = 0x05, +}; + +enum atsc_vct_service_type { + ATSC_VCT_SERVICE_TYPE_ANALOG = 0x01, + ATSC_VCT_SERVICE_TYPE_TV = 0x02, + ATSC_VCT_SERVICE_TYPE_AUDIO = 0x03, + ATSC_VCT_SERVICE_TYPE_DATA = 0x04, +}; + +enum atsc_etm_location { + ATSC_VCT_ETM_NONE = 0x00, + ATSC_VCT_ETM_IN_THIS_PTC = 0x01, + ATSC_VCT_ETM_IN_CHANNEL_TSID = 0x02, +}; + +enum atsc_text_compress_type { + ATSC_TEXT_COMPRESS_NONE = 0x00, + ATSC_TEXT_COMPRESS_PROGRAM_TITLE = 0x01, + ATSC_TEXT_COMPRESS_PROGRAM_DESCRIPTION = 0x02, +}; + +enum atsc_text_segment_mode { + ATSC_TEXT_SEGMENT_MODE_UNICODE_RANGE_MIN = 0x00, + ATSC_TEXT_SEGMENT_MODE_UNICODE_RANGE_MAX = 0x33, + ATSC_TEXT_SEGMENT_MODE_SCSU = 0x3e, + ATSC_TEXT_SEGMENT_MODE_UTF16 = 0x3f, + ATSC_TEXT_SEGMENT_MODE_TAIWAN_BITMAP = 0x40, + ATSC_TEXT_SEGMENT_MODE_TAIWAN_CODEWORD_BITMAP = 0x41, +}; + +typedef uint32_t atsctime_t; + +struct atsc_text { + uint8_t number_strings; + /* struct atsc_text_string strings[] */ +}; + +struct atsc_text_string { + iso639lang_t language_code; + uint8_t number_segments; + /* struct atsc_text_string_segment segments[] */ +}; + +struct atsc_text_string_segment { + uint8_t compression_type; + uint8_t mode; + uint8_t number_bytes; + /* uint8_t bytes[] */ +}; + +/** + * Iterator for strings field of an atsc_text structure. + * + * @param txt atsc_text pointer. + * @param pos Variable holding a pointer to the current atsc_text_string. + * @param idx Iterator variable. + */ +#define atsc_text_strings_for_each(txt, pos, idx) \ + for ((pos) = atsc_text_strings_first(txt), idx=0; \ + (pos); \ + (pos) = atsc_text_strings_next(txt, pos, ++idx)) + +/** + * Iterator for segments field of an atsc_text_string structure. + * + * @param str atsc_text_string pointer. + * @param pos Variable holding a pointer to the current atsc_text_string_segment. + * @param idx Iterator variable. + */ +#define atsc_text_string_segments_for_each(str, pos, idx) \ + for ((pos) = atsc_text_string_segments_first(str), idx=0; \ + (pos); \ + (pos) = atsc_text_string_segments_next(str, pos, ++idx)) + +/** + * Accessor for the bytes field of an atsc_text_string_segment. + * + * @param seg atsc_text_string_segment pointer. + * @return Pointer to the bytes. + */ +static inline uint8_t* + atsc_text_string_segment_bytes(struct atsc_text_string_segment *d) +{ + return ((uint8_t*) d) + sizeof(struct atsc_text_string_segment); +} + +/** + * Validate a buffer containing an atsc_text structure. + * + * @param buf Start of the atsc_text structure. + * @param len Length in bytes of the buffer. + * @return 0 if valid, nonzero if not. + */ +extern int atsc_text_validate(uint8_t *buf, int len); + +/** + * Decodes an atsc_text_segment with mode < 0x3e. Decompression of the ATSC text encoding IS + * supported. The output text will be in the UTF-8 encoding. + * + * @param segment Pointer to the segment to decode. + * @param destbuf Pointer to the malloc()ed buffer to append text to (pass NULL if none). + * @param destbufsize Size of destbuf in bytes. + * @param destbufpos Position within destbuf. This will be updated to point after the end of the + * string on exit. + * @return New value of destbufpos, or < 0 on error. + */ +extern int atsc_text_segment_decode(struct atsc_text_string_segment *segment, + uint8_t **destbuf, size_t *destbufsize, size_t *destbufpos); + +/** + * Convert from ATSC time to unix time_t. + * + * @param atsc ATSC time. + * @return The time value. + */ +extern time_t atsctime_to_unixtime(atsctime_t atsc); + +/** + * Convert from unix time_t to atsc time. + * + * @param t unix time_t. + * @return The atsc time value. + */ +extern atsctime_t unixtime_to_atsctime(time_t t); + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct atsc_text_string* + atsc_text_strings_first(struct atsc_text *txt) +{ + if (txt->number_strings == 0) + return NULL; + + return (struct atsc_text_string *) + ((uint8_t*) txt + sizeof(struct atsc_text)); +} + +static inline struct atsc_text_string* + atsc_text_strings_next(struct atsc_text *txt, struct atsc_text_string *pos, int idx) +{ + int i; + uint8_t *buf; + + if (idx >= txt->number_strings) + return NULL; + + buf = ((uint8_t*) pos) + sizeof(struct atsc_text_string); + for(i=0; i < pos->number_segments; i++) { + struct atsc_text_string_segment *seg = + (struct atsc_text_string_segment *) buf; + + buf += sizeof(struct atsc_text_string_segment); + buf += seg->number_bytes; + } + + return (struct atsc_text_string *) buf; +} + +static inline struct atsc_text_string_segment* + atsc_text_string_segments_first(struct atsc_text_string *str) +{ + if (str->number_segments == 0) + return NULL; + + return (struct atsc_text_string_segment *) + ((uint8_t*) str + sizeof(struct atsc_text_string)); +} + +static inline struct atsc_text_string_segment* + atsc_text_string_segments_next(struct atsc_text_string *str, + struct atsc_text_string_segment *pos, int idx) +{ + if (idx >= str->number_segments) + return NULL; + + return (struct atsc_text_string_segment *) + (((uint8_t*) pos) + sizeof(struct atsc_text_string_segment) + pos->number_bytes); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/crc32.h b/kaffeine/src/input/dvb/lib/libucsi/crc32.h index 5d77e84..7d781ce 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/crc32.h +++ b/kaffeine/src/input/dvb/lib/libucsi/crc32.h @@ -40,9 +40,9 @@ extern uint32_t crc32tbl[]; * @param len Number of bytes. * @return Calculated CRC. */ -static inline uint32_t crc32(uint32_t crc, uint8_t* buf, int len) +static inline uint32_t crc32(uint32_t crc, uint8_t* buf, size_t len) { - int i; + size_t i; for (i=0; i< len; i++) { crc = (crc << 8) ^ crc32tbl[((crc >> 24) ^ buf[i]) & 0xff]; diff --git a/kaffeine/src/input/dvb/lib/libucsi/descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/descriptor.h index 809936d..606e45d 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/descriptor.h @@ -47,7 +47,7 @@ struct descriptor { * @return Pointer to next descriptor, or NULL if there are none. */ static inline struct descriptor * - next_descriptor(uint8_t * buf, int len, struct descriptor * pos) + next_descriptor(uint8_t * buf, size_t len, struct descriptor * pos) { uint8_t* next; @@ -105,9 +105,9 @@ static inline int /******************************** PRIVATE CODE ********************************/ -static inline int verify_descriptors(uint8_t * buf, int len) +static inline int verify_descriptors(uint8_t * buf, size_t len) { - int pos = 0; + size_t pos = 0; while (pos < len) { if ((pos + 2) > len) diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/ac3_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/ac3_descriptor.h index d60e37b..0a2a5cd 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/ac3_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/ac3_descriptor.h @@ -40,7 +40,7 @@ struct dvb_ac3_descriptor { uint8_t bsid_flag : 1; , uint8_t mainid_flag : 1; , uint8_t asvc_flag : 1; , - uint8_t reserved : 4; ) + uint8_t reserved : 4; ); /* uint8_t additional_info[] */ } __ucsi_packed; diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/adaptation_field_data_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/adaptation_field_data_descriptor.h index 69a21b8..b207054 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/adaptation_field_data_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/adaptation_field_data_descriptor.h @@ -37,7 +37,7 @@ struct dvb_adaptation_field_data_descriptor { struct descriptor d; EBIT2(uint8_t reserved : 7; , - uint8_t announcement_switching_data : 1; ) + uint8_t announcement_switching_data : 1; ); } __ucsi_packed; /** diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_descriptor.h index 877d9c0..95fb7e3 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_descriptor.h @@ -36,7 +36,7 @@ extern "C" enum { AVB_AIT_APPLICATION_VISIBILITY_HIDDEN = 0x00, AVB_AIT_APPLICATION_VISIBILITY_APPSONLY = 0x01, - AVB_AIT_APPLICATION_VISIBILITY_VISIBLE = 0x03 + AVB_AIT_APPLICATION_VISIBILITY_VISIBLE = 0x03, }; /** @@ -66,7 +66,7 @@ struct dvb_ait_application_profile { struct dvb_ait_application_descriptor_part2 { EBIT3(uint8_t service_bound_flag : 1; , uint8_t visibility : 2; , - uint8_t reserved : 5; ) + uint8_t reserved : 5; ); uint8_t application_priority; /* uint8_t transport_protocol_label[] */ } __ucsi_packed; diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_icons_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_icons_descriptor.h index 5ea5932..431cd6c 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_icons_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_icons_descriptor.h @@ -45,7 +45,7 @@ enum { AIT_APPLICATION_ICON_FLAG_128_128 = 0x040, AIT_APPLICATION_ICON_FLAG_128_128_43 = 0x080, - AIT_APPLICATION_ICON_FLAG_96_128_169 = 0x100 + AIT_APPLICATION_ICON_FLAG_96_128_169 = 0x100, }; /** diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/ancillary_data_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/ancillary_data_descriptor.h index 7a0280d..04b2f59 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/ancillary_data_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/ancillary_data_descriptor.h @@ -42,7 +42,7 @@ struct dvb_ancillary_data_descriptor { uint8_t dab_ancillary_data : 1; , uint8_t announcement_switching_data : 1; , uint8_t extended_ancillary_data : 1; , - uint8_t dvd_video_ancillary_data : 1; ) + uint8_t dvd_video_ancillary_data : 1; ); } __ucsi_packed; /** diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/announcement_support_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/announcement_support_descriptor.h index 55a570b..9eb20c4 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/announcement_support_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/announcement_support_descriptor.h @@ -41,7 +41,7 @@ enum { DVB_ANNOUNCEMENT_SUPPORT_NEWS_FLASH = 0x10, DVB_ANNOUNCEMENT_SUPPORT_WEATHER_FLASH = 0x20, DVB_ANNOUNCEMENT_SUPPORT_EVENT_ANNOUNCEMENT = 0x40, - DVB_ANNOUNCEMENT_SUPPORT_PERSONAL_CALL = 0x80 + DVB_ANNOUNCEMENT_SUPPORT_PERSONAL_CALL = 0x80, }; /** @@ -55,7 +55,7 @@ enum { DVB_ANNOUNCEMENT_TYPE_NEWS_FLASH = 0x04, DVB_ANNOUNCEMENT_TYPE_WEATHER_FLASH = 0x05, DVB_ANNOUNCEMENT_TYPE_EVENT_ANNOUNCEMENT = 0x06, - DVB_ANNOUNCEMENT_TYPE_PERSONAL_CALL = 0x07 + DVB_ANNOUNCEMENT_TYPE_PERSONAL_CALL = 0x07, }; /** @@ -65,7 +65,7 @@ enum { DVB_REFERENCE_TYPE_AUDIO = 0x00, DVB_REFERENCE_TYPE_OTHER_AUDIO = 0x01, DVB_REFERENCE_TYPE_OTHER_SERVICE = 0x02, - DVB_REFERENCE_TYPE_OTHER_TS = 0x03 + DVB_REFERENCE_TYPE_OTHER_TS = 0x03, }; /** @@ -83,7 +83,7 @@ struct dvb_announcement_support_descriptor { struct dvb_announcement_support_entry { EBIT3(uint8_t announcement_type : 4; , uint8_t reserved : 1; , - uint8_t reference_type : 3; ) + uint8_t reference_type : 3; ); /* Only if reference_type == 1, 2 or 3: * struct dvb_announcement_support_reference reference */ } __ucsi_packed; diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/application_signalling_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/application_signalling_descriptor.h index c1d50ff..78211cf 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/application_signalling_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/application_signalling_descriptor.h @@ -45,7 +45,7 @@ struct dvb_application_signalling_descriptor { struct dvb_application_signalling_entry { uint16_t application_type; EBIT2(uint8_t reserved : 3; , - uint8_t AIT_version_number : 5; ) + uint8_t AIT_version_number : 5; ); } __ucsi_packed; /** @@ -105,8 +105,8 @@ static inline struct dvb_application_signalling_entry* } static inline struct dvb_application_signalling_entry* - dvb_application_signalling_descriptor_countries_next(struct dvb_application_signalling_descriptor *d, - struct dvb_application_signalling_entry *pos) + dvb_application_signalling_descriptor_entries_next(struct dvb_application_signalling_descriptor *d, + struct dvb_application_signalling_entry *pos) { uint8_t *end = (uint8_t*) d + 2 + d->d.len; uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_application_signalling_entry); diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/bat_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/bat_section.c index afbeb0f..99e5cf6 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/bat_section.c +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/bat_section.c @@ -24,8 +24,8 @@ struct dvb_bat_section * dvb_bat_section_codec(struct section_ext * ext) { uint8_t * buf = (uint8_t *) ext; - unsigned int pos = sizeof(struct section_ext); - unsigned int len = section_ext_length(ext); + size_t pos = sizeof(struct section_ext); + size_t len = section_ext_length(ext); struct dvb_bat_section * ret = (struct dvb_bat_section *) ext; if (len < sizeof(struct dvb_bat_section)) diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/bat_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/bat_section.h index 277d5ab..94ed8a4 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/bat_section.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/bat_section.h @@ -71,7 +71,7 @@ struct dvb_bat_section *dvb_bat_section_codec(struct section_ext *section); /** * Accessor for the bouquet_id field of a BAT. - * + * * @param bat BAT pointer. * @return The bouquet_id. */ diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/cable_delivery_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/cable_delivery_descriptor.h index 70b0c98..f0f92f3 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/cable_delivery_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/cable_delivery_descriptor.h @@ -38,10 +38,10 @@ struct dvb_cable_delivery_descriptor { uint32_t frequency; // BCD, units 100Hz EBIT2(uint16_t reserved : 12; , - uint16_t fec_outer : 4; ) + uint16_t fec_outer : 4; ); uint8_t modulation; EBIT2(uint32_t symbol_rate : 28; , // BCD, units 100Hz - uint32_t fec_inner : 4; ) + uint32_t fec_inner : 4; ); } __ucsi_packed; /** diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/cell_frequency_link_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/cell_frequency_link_descriptor.h index b6285bd..63f7fd2 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/cell_frequency_link_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/cell_frequency_link_descriptor.h @@ -160,7 +160,7 @@ static inline struct dvb_cell_frequency_link_cell* } static inline struct dvb_cell_frequency_link_cell_subcell* - dvb_cell_frequency_cell_subcells_first(struct dvb_cell_frequency_link_cell *d) + dvb_cell_frequency_link_cell_subcells_first(struct dvb_cell_frequency_link_cell *d) { if (d->subcell_loop_info_length == 0) return NULL; @@ -170,7 +170,7 @@ static inline struct dvb_cell_frequency_link_cell_subcell* } static inline struct dvb_cell_frequency_link_cell_subcell* - dvb_cell_frequency_cell_subcells_next(struct dvb_cell_frequency_link_cell *cell, + dvb_cell_frequency_link_cell_subcells_next(struct dvb_cell_frequency_link_cell *cell, struct dvb_cell_frequency_link_cell_subcell *pos) { uint8_t *end = (uint8_t*) cell + cell->subcell_loop_info_length; diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/cell_list_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/cell_list_descriptor.h index 6a42ce4..ddbaf2c 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/cell_list_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/cell_list_descriptor.h @@ -48,7 +48,7 @@ struct dvb_cell_list_entry { uint16_t cell_longitude; EBIT3(uint32_t cell_extend_of_latitude :12; , uint32_t cell_extend_of_longitude :12; , - uint32_t subcell_info_loop_length : 8; ) + uint32_t subcell_info_loop_length : 8; ); /* struct dvb_subcell_list_entry subcells[] */ } __ucsi_packed; @@ -60,7 +60,7 @@ struct dvb_subcell_list_entry { uint16_t subcell_latitude; uint16_t subcell_longitude; EBIT2(uint32_t subcell_extend_of_latitude :12; , - uint32_t subcell_extend_of_longitude :12; ) + uint32_t subcell_extend_of_longitude :12; ); } __ucsi_packed; /** diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/component_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/component_descriptor.h index 154e235..31d38e1 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/component_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/component_descriptor.h @@ -38,7 +38,7 @@ enum { DVB_STREAM_CONTENT_VIDEO = 0x01, DVB_STREAM_CONTENT_AUDIO = 0x02, DVB_STREAM_CONTENT_SUBTITLE = 0x03, - DVB_STREAM_CONTENT_AC3 = 0x04 + DVB_STREAM_CONTENT_AC3 = 0x04, }; /** @@ -84,7 +84,7 @@ enum { DVB_COMPONENT_TYPE_SUBTITLE_DVB_HARDHEAR = 0x20, DVB_COMPONENT_TYPE_SUBTITLE_DVB_HARDHEAR_43 = 0x21, DVB_COMPONENT_TYPE_SUBTITLE_DVB_HARDHEAR_169 = 0x22, - DVB_COMPONENT_TYPE_SUBTITLE_DVB_HARDHEAR_2211 = 0x23 + DVB_COMPONENT_TYPE_SUBTITLE_DVB_HARDHEAR_2211 = 0x23, }; /** @@ -94,7 +94,7 @@ struct dvb_component_descriptor { struct descriptor d; EBIT2(uint8_t reserved : 4; , - uint8_t stream_content : 4; ) + uint8_t stream_content : 4; ); uint8_t component_type; uint8_t component_tag; iso639lang_t language_code; diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/content_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/content_descriptor.h index 5cc16dc..d2a63a0 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/content_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/content_descriptor.h @@ -46,9 +46,9 @@ struct dvb_content_descriptor { */ struct dvb_content_nibble { EBIT2(uint8_t content_nibble_level_1 : 4; , - uint8_t content_nibble_level_2 : 4; ) + uint8_t content_nibble_level_2 : 4; ); EBIT2(uint8_t user_nibble_1 : 4; , - uint8_t user_nibble_2 : 4; ) + uint8_t user_nibble_2 : 4; ); } __ucsi_packed; /** diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/content_identifier_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/content_identifier_descriptor.h index 63d24a1..c2cf9ea 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/content_identifier_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/content_identifier_descriptor.h @@ -39,7 +39,7 @@ enum { DVB_CRID_TYPE_NONE = 0x00, DVB_CRID_TYPE_ITEM = 0x01, DVB_CRID_TYPE_SERIES = 0x02, - DVB_CRID_TYPE_RECOMMENDATION = 0x03 + DVB_CRID_TYPE_RECOMMENDATION = 0x03, }; /** @@ -47,7 +47,7 @@ enum { */ enum { DVB_CRID_LOCATION_THIS_DESCRIPTOR = 0x00, - DVB_CRID_LOCATION_CIT = 0x01 + DVB_CRID_LOCATION_CIT = 0x01, }; /** @@ -64,7 +64,7 @@ struct dvb_content_identifier_descriptor { */ struct dvb_content_identifier_entry { EBIT2(uint8_t crid_type : 6; , - uint8_t crid_location : 2; ) + uint8_t crid_location : 2; ); /* struct dvb_content_identifier_data_00 data0 */ /* struct dvb_content_identifier_data_01 data1 */ } __ucsi_packed; @@ -154,6 +154,17 @@ static inline struct dvb_content_identifier_entry_data_0* return (struct dvb_content_identifier_entry_data_0*) ((uint8_t*) d + sizeof(struct dvb_content_identifier_entry)); } +/** + * Accessor for the data field of a dvb_content_identifier_entry_data_0. + * + * @param d dvb_content_identifier_entry_data_0 pointer. + * @return Pointer, or NULL on error. + */ +static inline uint8_t* + dvb_content_identifier_entry_data_0_data(struct dvb_content_identifier_entry_data_0 *d) +{ + return ((uint8_t*) d + sizeof(struct dvb_content_identifier_entry_data_0)); +} /** * Accessor for the data1 field of a dvb_content_identifier_entry. diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/country_availability_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/country_availability_descriptor.h index 29a6b9a..65b1661 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/country_availability_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/country_availability_descriptor.h @@ -38,7 +38,7 @@ struct dvb_country_availability_descriptor { struct descriptor d; EBIT2(uint8_t country_availability_flag : 1; , - uint8_t reserved : 7; ) + uint8_t reserved : 7; ); /* struct dvb_country_availability_entry countries[] */ } __ucsi_packed; diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/data_broadcast_id_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/data_broadcast_id_descriptor.h index 8547d8f..446927c 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/data_broadcast_id_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/data_broadcast_id_descriptor.h @@ -31,6 +31,23 @@ extern "C" #include <libucsi/endianops.h> /** + * Possible values for data_broadcast_id. + */ +enum { + DVB_BROADCAST_ID_DATA_PIPE = 0X0001, + DVB_BROADCAST_ID_ASYNCHRONOUS_DATA_STREAM = 0X0002, + DVB_BROADCAST_ID_SYNCHRONOUS_DATA_STREAM = 0X0003, + DVB_BROADCAST_ID_SYNCHRONISED_DATA_STREAM = 0X0004, + DVB_BROADCAST_ID_MULTI_PROTOCOL_ENCAPSULATION = 0X0005, + DVB_BROADCAST_ID_DATA_CAROUSEL = 0X0006, + DVB_BROADCAST_ID_OBJECT_CAROUSEL = 0X0007, + DVB_BROADCAST_ID_DVB_ATM_STREAMS = 0X0008, + DVB_BROADCAST_ID_HIGHER_PROTOCOLS = 0X0009, + DVB_BROADCAST_ID_SOFTWARE_UPDATE = 0x000A, + DVB_BROADCAST_ID_IP_MAC_NOTIFICATION_TABLE = 0x000B, +}; + +/** * dvb_data_broadcast_id_descriptor structure. */ struct dvb_data_broadcast_id_descriptor { @@ -41,6 +58,26 @@ struct dvb_data_broadcast_id_descriptor { } __ucsi_packed; /** + * id_selector_byte for 0x000b data_broadcast_id (IP/MAC Notification Table). + */ +struct dvb_id_selector_byte_000b { + uint8_t platform_id_data_length; + /* struct dvb_ip_mac_notification_info infos[] */ + /* uint8_t private_data[] */ +} __ucsi_packed; + +/** + * Entries in the infos field of a dvb_id_selector_byte_0b. + */ +struct dvb_ip_mac_notification_info { + EBIT2(uint32_t platform_id : 24; , + uint8_t action_type : 8; ); + EBIT3(uint8_t reserved : 2; , + uint8_t INT_versioning_flag : 1; , + uint8_t INT_version : 5; ); +} __ucsi_packed; + +/** * Process a dvb_data_broadcast_id_descriptor. * * @param d Generic descriptor structure. @@ -81,6 +118,100 @@ static inline int return d->d.len - 2; } +/** + * Accessor for a dvb_id_selector_byte_000b pointer. + * + * @param d dvb_data_broadcast_id_descriptor pointer. + * @return Pointer to the data field. + */ +static inline struct dvb_id_selector_byte_000b * + dvb_id_selector_byte_000b(struct dvb_data_broadcast_id_descriptor *d) +{ + if (d->data_broadcast_id != DVB_BROADCAST_ID_IP_MAC_NOTIFICATION_TABLE) + return NULL; + return (struct dvb_id_selector_byte_000b *) dvb_data_broadcast_id_descriptor_id_selector_byte(d); +} + +/** + * Iterator for the dvb_ip_mac_notification_info field of a dvb_id_selector_byte_000b. + * + * @param id_selector_byte dvb_id_selector_byte_000b pointer. + * @param pos Variable containing a pointer to the current dvb_ip_mac_notification_info. + */ +#define dvb_id_selector_byte_000b_ip_mac_notification_info_for_each(id_selector_byte, pos) \ + for ((pos) = dvb_ip_mac_notification_info_first(id_selector_byte); \ + (pos); \ + (pos) = dvb_ip_mac_notification_info_next(id_selector_byte, pos)) + +/** + * Length of the private_data field of a dvb_id_selector_byte_000b. + * + * @param d descriptor pointer. + * @param i dvb_id_selector_byte_000b pointer. + * @return Length of the field. + */ +static inline uint8_t + dvb_id_selector_byte_000b_private_data_length(struct descriptor *d, + struct dvb_id_selector_byte_000b *i) +{ + return (uint8_t) (d->len - + sizeof(struct descriptor) - + i->platform_id_data_length - + sizeof(struct dvb_id_selector_byte_000b)); +} + +/** + * Accessor for the private_data field of a dvb_id_selector_byte_000b. + * + * @param d descriptor pointer. + * @param i dvb_id_selector_byte_000b pointer. + * @return Pointer to the field. + */ +static inline uint8_t * + dvb_id_selector_byte_000b_private_data(struct descriptor *d, + struct dvb_id_selector_byte_000b *i) +{ + if (dvb_id_selector_byte_000b_private_data_length(d, i) <= 0) + return NULL; + + return (uint8_t *) i + i->platform_id_data_length + sizeof(struct dvb_id_selector_byte_000b); +} + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_ip_mac_notification_info * + dvb_ip_mac_notification_info_first(struct dvb_id_selector_byte_000b *d) +{ + if (d->platform_id_data_length == 0) + return NULL; + + bswap32((uint8_t *) d + sizeof(struct dvb_id_selector_byte_000b)); + + return (struct dvb_ip_mac_notification_info *) ((uint8_t *) d + sizeof(struct dvb_id_selector_byte_000b)); +} + +static inline struct dvb_ip_mac_notification_info * + dvb_ip_mac_notification_info_next(struct dvb_id_selector_byte_000b *d, + struct dvb_ip_mac_notification_info *pos) +{ + uint8_t *end = (uint8_t *) d + d->platform_id_data_length; + uint8_t *next = (uint8_t *) pos + + sizeof(struct dvb_id_selector_byte_000b) + + sizeof(struct dvb_ip_mac_notification_info); + + if (next >= end) + return NULL; + + bswap32(next); + + return (struct dvb_ip_mac_notification_info *) next; +} + #ifdef __cplusplus } #endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/descriptor.h index 0772601..345f6f0 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/descriptor.h @@ -47,6 +47,9 @@ extern "C" #include <libucsi/dvb/dsng_descriptor.h> #include <libucsi/dvb/extended_event_descriptor.h> #include <libucsi/dvb/frequency_list_descriptor.h> +#include <libucsi/dvb/ip_mac_platform_name_descriptor.h> +#include <libucsi/dvb/ip_mac_platform_provider_name_descriptor.h> +#include <libucsi/dvb/ip_mac_stream_location_descriptor.h> #include <libucsi/dvb/linkage_descriptor.h> #include <libucsi/dvb/local_time_offset_descriptor.h> #include <libucsi/dvb/mosaic_descriptor.h> @@ -74,15 +77,28 @@ extern "C" #include <libucsi/dvb/stream_identifier_descriptor.h> #include <libucsi/dvb/stuffing_descriptor.h> #include <libucsi/dvb/subtitling_descriptor.h> +#include <libucsi/dvb/target_ip_address_descriptor.h> +#include <libucsi/dvb/target_ipv6_address_descriptor.h> +#include <libucsi/dvb/target_ip_slash_descriptor.h> +#include <libucsi/dvb/target_ip_source_slash_descriptor.h> +#include <libucsi/dvb/target_ipv6_slash_descriptor.h> +#include <libucsi/dvb/target_ipv6_source_slash_descriptor.h> #include <libucsi/dvb/telephone_descriptor.h> #include <libucsi/dvb/teletext_descriptor.h> #include <libucsi/dvb/terrestrial_delivery_descriptor.h> #include <libucsi/dvb/time_shifted_event_descriptor.h> #include <libucsi/dvb/time_shifted_service_descriptor.h> +#include <libucsi/dvb/time_slice_fec_identifier_descriptor.h> #include <libucsi/dvb/transport_stream_descriptor.h> #include <libucsi/dvb/tva_id_descriptor.h> #include <libucsi/dvb/vbi_data_descriptor.h> #include <libucsi/dvb/vbi_teletext_descriptor.h> +#include <libucsi/endianops.h> + +/** + * The following are disabled because support is incomplete just now. + */ +/* #include <libucsi/dvb/rnt_rar_over_dvb_stream_descriptor.h> #include <libucsi/dvb/rnt_rar_over_ip_descriptor.h> #include <libucsi/dvb/rnt_rnt_scan_descriptor.h> @@ -90,7 +106,7 @@ extern "C" #include <libucsi/dvb/ait_application_name_descriptor.h> #include <libucsi/dvb/ait_external_application_authorisation_descriptor.h> #include <libucsi/dvb/ait_application_icons_descriptor.h> -#include <libucsi/endianops.h> +*/ /** * The following are not implemented just now @@ -169,6 +185,10 @@ enum dvb_descriptor_tag { dtag_dvb_time_slice_fec_identifier = 0x77, dtag_dvb_ecm_repetition_rate = 0x78, dtag_dvb_s2_satellite_delivery_descriptor= 0x79, + dtag_dvb_enhanced_ac3_descriptor = 0x7a, + dtag_dvb_dts_descriptor = 0x7b, + dtag_dvb_aac_descriptor = 0x7c, + dtag_dvb_extension_descriptor = 0x7f, /* descriptors which may only appear in an RNT */ dtag_dvb_rnt_rar_over_dvb_stream = 0x40, @@ -188,8 +208,20 @@ enum dvb_descriptor_tag { dtag_dvb_ait_application_icons = 0x0b, dtag_dvb_ait_prefetch = 0x0c, dtag_dvb_ait_dii_location = 0x0d, - dtag_dvb_ait_ip_signalling = 0x11 -};/*__ucsi_packed;*/ + dtag_dvb_ait_ip_signalling = 0x11, + + /* descriptors which may only appear in INT */ + dtag_dvb_target_ip_address = 0x09, + dtag_dvb_target_ipv6_address = 0x0a, + dtag_dvb_ip_mac_platform_name = 0x0c, + dtag_dvb_ip_mac_platform_provider_name = 0x0d, + dtag_dvb_target_ip_slash = 0x0f, + dtag_dvb_target_ip_source_slash = 0x10, + dtag_dvb_target_ipv6_slash = 0x11, + dtag_dvb_target_ipv6_source_slash = 0x12, + dtag_dvb_ip_mac_stream_location = 0x13, + +}; #ifdef __cplusplus } diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/eit_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/eit_section.c index ce22a58..97b0261 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/eit_section.c +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/eit_section.c @@ -24,9 +24,9 @@ struct dvb_eit_section *dvb_eit_section_codec(struct section_ext * ext) { uint8_t * buf = (uint8_t *) ext; - unsigned int pos = sizeof(struct section_ext); - unsigned int len = section_ext_length(ext); - + size_t pos = sizeof(struct section_ext); + size_t len = section_ext_length(ext); + if (len < sizeof(struct dvb_eit_section)) return NULL; @@ -34,14 +34,14 @@ struct dvb_eit_section *dvb_eit_section_codec(struct section_ext * ext) pos += 2; bswap16(buf + pos); pos += 4; - + while (pos < len) { struct dvb_eit_event * event = (struct dvb_eit_event *) (buf + pos); if ((pos + sizeof(struct dvb_eit_event)) > len) return NULL; - + bswap16(buf + pos); bswap16(buf + pos + 10); diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/eit_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/eit_section.h index 9064224..a2f3e4f 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/eit_section.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/eit_section.h @@ -67,7 +67,7 @@ struct dvb_eit_section *dvb_eit_section_codec(struct section_ext *section); /** * Accessor for the service_id field of an EIT. - * + * * @param eit EIT pointer. * @return The service_id. */ @@ -111,7 +111,7 @@ static inline uint16_t dvb_eit_section_service_id(struct dvb_eit_section *eit) static inline struct dvb_eit_event * dvb_eit_section_events_first(struct dvb_eit_section *eit) { - int pos = sizeof(struct dvb_eit_section); + size_t pos = sizeof(struct dvb_eit_section); if (pos >= section_ext_length(&eit->head)) return NULL; diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/extended_event_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/extended_event_descriptor.h index 82d580b..bba04b0 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/extended_event_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/extended_event_descriptor.h @@ -38,7 +38,7 @@ struct dvb_extended_event_descriptor { struct descriptor d; EBIT2(uint8_t descriptor_number : 4; , - uint8_t last_descriptor_number : 4; ) + uint8_t last_descriptor_number : 4; ); iso639lang_t language_code; uint8_t length_of_items; /* struct dvb_extended_event_item items[] */ diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/frequency_list_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/frequency_list_descriptor.h index 4fca751..4c18cec 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/frequency_list_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/frequency_list_descriptor.h @@ -36,7 +36,7 @@ extern "C" enum { DVB_CODING_TYPE_SATELLITE = 0x01, DVB_CODING_TYPE_CABLE = 0x02, - DVB_CODING_TYPE_TERRESTRIAL = 0x03 + DVB_CODING_TYPE_TERRESTRIAL = 0x03, }; /** @@ -46,7 +46,7 @@ struct dvb_frequency_list_descriptor { struct descriptor d; EBIT2(uint8_t reserved : 6; , - uint8_t coding_type : 2; ) + uint8_t coding_type : 2; ); /* uint32_t centre_frequencies [] */ } __ucsi_packed; diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/int_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/int_section.c index a6ddd6e..c2bb15f 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/int_section.c +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/int_section.c @@ -26,16 +26,15 @@ struct dvb_int_section * dvb_int_section_codec(struct section_ext *ext) { uint8_t *buf = (uint8_t *) ext; struct dvb_int_section *in = (struct dvb_int_section *) ext; - - unsigned int pos = sizeof(struct section_ext); - unsigned int len = section_ext_length(ext); + size_t pos = sizeof(struct section_ext); + size_t len = section_ext_length(ext); if (len < sizeof(struct dvb_int_section)) return NULL; bswap32(buf+8); bswap16(buf+12); - pos += 9; + pos += 6; if (len - pos < in->platform_descriptors_length) return NULL; diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/int_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/int_section.h index 71ba1e8..932c0e8 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/int_section.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/int_section.h @@ -72,7 +72,7 @@ extern struct dvb_int_section * dvb_int_section_codec(struct section_ext *sectio /** * Accessor for the action_type field of an INT. - * + * * @param intp INT pointer. * @return The action_type. */ @@ -83,7 +83,7 @@ static inline uint8_t dvb_int_section_action_type(struct dvb_int_section *intp) /** * Accessor for the platform_id_hash field of an INT. - * + * * @param intp INT pointer. * @return The platform_id_hash. */ diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/ip_mac_platform_name_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/ip_mac_platform_name_descriptor.h new file mode 100644 index 0000000..c470e89 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/ip_mac_platform_name_descriptor.h @@ -0,0 +1,87 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * Copyright (C) 2006 Stephane Este-Gracias (sestegra@free.fr) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_IP_MAC_PLATFORM_NAME_DESCRIPTOR +#define _UCSI_DVB_IP_MAC_PLATFORM_NAME_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/types.h> + +/** + * dvb_ip_platform_name_descriptor structure. + */ +struct dvb_ip_platform_name_descriptor { + struct descriptor d; + + iso639lang_t language_code; + /* uint8_t text[] */ +} __ucsi_packed; + +/** + * Process a dvb_ip_platform_name_descriptor. + * + * @param d Pointer to a generic descriptor. + * @return dvb_ip_platform_name_descriptor pointer, or NULL on error. + */ +static inline struct dvb_ip_platform_name_descriptor* + dvb_ip_platform_name_descriptor_codec(struct descriptor* d) +{ + if (d->len < (sizeof(struct dvb_ip_platform_name_descriptor) - 2)) + return NULL; + + return (struct dvb_ip_platform_name_descriptor*) d; +} + +/** + * Accessor for the text field of a dvb_ip_platform_name_descriptor. + * + * @param d dvb_ip_platform_name_descriptor pointer. + * @return Pointer to the field. + */ +static inline uint8_t * + dvb_ip_platform_name_descriptor_text(struct dvb_ip_platform_name_descriptor *d) +{ + return (uint8_t *) d + sizeof(struct dvb_ip_platform_name_descriptor); +} + +/** + * Determine the length of the text field of a dvb_ip_platform_name_descriptor. + * + * @param d dvb_ip_platform_name_descriptor pointer. + * @return Length of the field in bytes. + */ +static inline int + dvb_ip_platform_name_descriptor_text_length(struct dvb_ip_platform_name_descriptor *d) +{ + return d->d.len - 3; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/ip_mac_platform_provider_name_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/ip_mac_platform_provider_name_descriptor.h new file mode 100644 index 0000000..ba95b8f --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/ip_mac_platform_provider_name_descriptor.h @@ -0,0 +1,87 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * Copyright (C) 2006 Stephane Este-Gracias (sestegra@free.fr) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_IP_MAC_PLATFORM_PROVIDER_NAME_DESCRIPTOR +#define _UCSI_DVB_IP_MAC_PLATFORM_PROVIDER_NAME_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/types.h> + +/** + * dvb_ip_platform_provider_name_descriptor structure. + */ +struct dvb_ip_platform_provider_name_descriptor { + struct descriptor d; + + iso639lang_t language_code; + /* uint8_t text[] */ +} __ucsi_packed; + +/** + * Process a dvb_ip_platform_provider_name_descriptor. + * + * @param d Pointer to a generic descriptor. + * @return dvb_ip_platform_provider_name_descriptor pointer, or NULL on error. + */ +static inline struct dvb_ip_platform_provider_name_descriptor* + dvb_ip_platform_provider_name_descriptor_codec(struct descriptor* d) +{ + if (d->len < (sizeof(struct dvb_ip_platform_provider_name_descriptor) - 2)) + return NULL; + + return (struct dvb_ip_platform_provider_name_descriptor*) d; +} + +/** + * Accessor for the text field of a dvb_ip_platform_provider_name_descriptor. + * + * @param d dvb_ip_platform_provider_name_descriptor pointer. + * @return Pointer to the field. + */ +static inline uint8_t * + dvb_ip_platform_provider_name_descriptor_text(struct dvb_ip_platform_provider_name_descriptor *d) +{ + return (uint8_t *) d + sizeof(struct dvb_ip_platform_provider_name_descriptor); +} + +/** + * Determine the length of the text field of a dvb_ip_platform_provider_name_descriptor. + * + * @param d dvb_ip_platform_provider_name_descriptor pointer. + * @return Length of the field in bytes. + */ +static inline int + dvb_ip_platform_provider_name_descriptor_text_length(struct dvb_ip_platform_provider_name_descriptor *d) +{ + return d->d.len - 3; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/ip_mac_stream_location_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/ip_mac_stream_location_descriptor.h new file mode 100644 index 0000000..36216d6 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/ip_mac_stream_location_descriptor.h @@ -0,0 +1,73 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * Copyright (C) 2006 Stephane Este-Gracias (sestegra@free.fr) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_IP_MAC_STREAM_LOCATION_DESCRIPTOR +#define _UCSI_DVB_IP_MAC_PLATFORM_PROVIDER_NAME_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/types.h> + +/** + * dvb_ip_mac_stream_location_descriptor structure. + */ +struct dvb_ip_mac_stream_location_descriptor { + struct descriptor d; + + uint16_t network_id; + uint16_t original_network_id; + uint16_t transport_stream_id; + uint16_t service_id; + uint8_t component_tag; +} __ucsi_packed; + +/** + * Process a dvb_ip_mac_stream_location_descriptor. + * + * @param d Generic descriptor pointer. + * @return dvb_ip_mac_stream_location_descriptor pointer, or NULL on error. + */ +static inline struct dvb_ip_mac_stream_location_descriptor* + dvb_ip_mac_stream_location_descriptor_codec(struct descriptor* d) +{ + uint8_t* buf = (uint8_t*) d + 2; + + if (d->len != (sizeof(struct dvb_ip_mac_stream_location_descriptor) - 2)) + return NULL; + + bswap16(buf); + bswap16(buf+2); + bswap16(buf+4); + bswap16(buf+6); + + return (struct dvb_ip_mac_stream_location_descriptor*) d; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/linkage_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/linkage_descriptor.h index f3370c8..d2be789 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/linkage_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/linkage_descriptor.h @@ -46,7 +46,7 @@ enum { DVB_LINKAGE_TYPE_SOFTWARE_UPDATE = 0x09, DVB_LINKAGE_TYPE_TS_WITH_SSU_BAT_NIT = 0x0a, DVB_LINKAGE_TYPE_IP_MAC_NOTIFICATION = 0x0b, - DVB_LINKAGE_TYPE_TS_WITH_INT_BAT_NIT = 0x0c + DVB_LINKAGE_TYPE_TS_WITH_INT_BAT_NIT = 0x0c, }; /** @@ -55,7 +55,7 @@ enum { enum { DVB_HAND_OVER_TYPE_IDENTICAL_NEIGHBOURING_COUNTRY = 0x01, DVB_HAND_OVER_TYPE_LOCAL_VARIATION = 0x02, - DVB_HAND_OVER_TYPE_ASSOCIATED_SERVICE = 0x03 + DVB_HAND_OVER_TYPE_ASSOCIATED_SERVICE = 0x03, }; /** @@ -63,7 +63,7 @@ enum { */ enum { DVB_ORIGIN_TYPE_NIT = 0x00, - DVB_ORIGIN_TYPE_SDT = 0x01 + DVB_ORIGIN_TYPE_SDT = 0x01, }; /** @@ -85,7 +85,7 @@ struct dvb_linkage_descriptor { struct dvb_linkage_data_08 { EBIT3(uint8_t hand_over_type : 4; , uint8_t reserved : 3; , - uint8_t origin_type : 1; ) + uint8_t origin_type : 1; ); /* uint16_t network_id if hand_over_type == 1,2,3 */ /* uint16_t initial_service_id if origin_type = 0 */ /* uint8_t data[] */ @@ -104,7 +104,7 @@ struct dvb_linkage_data_0b { */ struct dvb_platform_id { EBIT2(uint32_t platform_id : 24; , - uint32_t platform_name_loop_length : 8; ) + uint8_t platform_name_loop_length : 8; ); /* struct platform_name names[] */ } __ucsi_packed; @@ -187,6 +187,8 @@ static inline struct dvb_linkage_descriptor* return NULL; while (pos2 < l_0b->platform_id_data_length) { + bswap32(buf + pos + pos2); + struct dvb_platform_id *p_id = (struct dvb_platform_id *) (buf + pos + pos2); if ((len - pos - pos2) < p_id->platform_name_loop_length) return NULL; @@ -359,7 +361,7 @@ static inline struct dvb_linkage_data_0b * * @param linkage dvb_linkage_data_0b pointer. * @param pos Variable containing a pointer to the current dvb_platform_id. */ -#define dvb_dvb_linkage_data_0b_platform_id_for_each(linkage, pos) \ +#define dvb_linkage_data_0b_platform_id_for_each(linkage, pos) \ for ((pos) = dvb_platform_id_first(linkage); \ (pos); \ (pos) = dvb_platform_id_next(linkage, pos)) diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/local_time_offset_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/local_time_offset_descriptor.h index 94932ff..d0eebb3 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/local_time_offset_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/local_time_offset_descriptor.h @@ -48,7 +48,7 @@ struct dvb_local_time_offset { iso639country_t country_code; EBIT3(uint8_t country_region_id : 6; , uint8_t reserved : 1; , - uint8_t local_time_offset_polarity : 1; ) + uint8_t local_time_offset_polarity : 1; ); dvbhhmm_t local_time_offset; dvbdate_t time_of_change; dvbhhmm_t next_time_offset; diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/mhp_data_broadcast_id_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/mhp_data_broadcast_id_descriptor.h index d5cf435..d79b48c 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/mhp_data_broadcast_id_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/mhp_data_broadcast_id_descriptor.h @@ -36,7 +36,7 @@ extern "C" */ enum { DVB_BROADCAST_ID_MHP_OBJECT_CAROUSEL = 0x00f0, - DVB_BROADCAST_ID_MHP_MPE = 0x00f1 + DVB_BROADCAST_ID_MHP_MPE = 0x00f1, }; /** diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/mosaic_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/mosaic_descriptor.h index 28838de..6da1e95 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/mosaic_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/mosaic_descriptor.h @@ -39,7 +39,7 @@ struct dvb_mosaic_descriptor { EBIT4(uint8_t mosaic_entry_point : 1; , uint8_t number_of_horiz_elementary_cells: 3; , uint8_t reserved : 1; , - uint8_t number_of_vert_elementary_cells : 3; ) + uint8_t number_of_vert_elementary_cells : 3; ); /* struct dvb_mosaic_info infos[] */ } __ucsi_packed; @@ -49,7 +49,7 @@ struct dvb_mosaic_descriptor { struct dvb_mosaic_info { EBIT3(uint16_t logical_cell_id : 6; , uint16_t reserved : 7; , - uint16_t logical_cell_presentation_info : 3; ) + uint16_t logical_cell_presentation_info : 3; ); uint8_t elementary_cell_field_length; /* struct dvb_mosaic_elementary_cell_field fields[] */ /* struct dvb_mosaic_info_part2 part2 */ @@ -61,7 +61,7 @@ struct dvb_mosaic_info { */ struct dvb_mosaic_elementary_cell_field { EBIT2(uint8_t reserved : 2; , - uint8_t elementary_cell_id : 6; ) + uint8_t elementary_cell_id : 6; ); } __ucsi_packed; /** diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/mpe_fec_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/mpe_fec_section.h new file mode 100644 index 0000000..6db0a47 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/mpe_fec_section.h @@ -0,0 +1,73 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * Copyright (C) 2008 Patrick Boettcher (pb@linuxtv.org) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_MPE_FEC_SECTION_H +#define _UCSI_DVB_MPE_FEC_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/mpeg/section.h> + +/** + * mpe_fec_section structure. TODO + */ +struct mpe_fec_section { + struct section head; +}; + + +/** + * real_time_paramters + * can also be found in datagram_section in MAC4-1-bytes */ +struct real_time_parameters { + EBIT4(uint32_t delta_t : 12; , + uint32_t table_boundary : 1; , + uint32_t frame_boundary : 1; , + uint32_t address : 18; ) +}; + + +static inline struct real_time_parameters * datagram_section_real_time_parameters_codec(struct datagram_section *d) +{ + struct real_time_parameters *rt = (struct real_time_parameters *) &d->MAC_address_4; + uint8_t b[4]; + b[0] = d->MAC_address_4; + b[1] = d->MAC_address_3; + b[2] = d->MAC_address_2; + b[3] = d->MAC_address_1; + + rt->delta_t = (b[0] << 4) | ((b[1] >> 4) & 0x0f); + rt->table_boundary = (b[1] >> 3) & 0x1; + rt->frame_boundary = (b[1] >> 2) & 0x1; + rt->address = ((b[1] & 0x3) << 16) | (b[2] << 8) | b[3]; + + return rt; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/nit_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/nit_section.c index d931926..664a0cb 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/nit_section.c +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/nit_section.c @@ -25,8 +25,8 @@ struct dvb_nit_section *dvb_nit_section_codec(struct section_ext * ext) { uint8_t * buf = (uint8_t *) ext; struct dvb_nit_section * ret = (struct dvb_nit_section *) ext; - unsigned int pos = sizeof(struct section_ext); - unsigned int len = section_ext_length(ext); + size_t pos = sizeof(struct section_ext); + size_t len = section_ext_length(ext); if (len < sizeof(struct dvb_nit_section)) return NULL; @@ -76,4 +76,3 @@ struct dvb_nit_section *dvb_nit_section_codec(struct section_ext * ext) return ret; } - diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/parental_rating_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/parental_rating_descriptor.h index 9acbcb0..72ecd0a 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/parental_rating_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/parental_rating_descriptor.h @@ -49,7 +49,7 @@ enum { DVB_PARENTAL_RATING_MIN_14YEARS = 0x0c, DVB_PARENTAL_RATING_MIN_15YEARS = 0x0d, DVB_PARENTAL_RATING_MIN_16YEARS = 0x0e, - DVB_PARENTAL_RATING_MIN_17YEARS = 0x0f + DVB_PARENTAL_RATING_MIN_17YEARS = 0x0f, }; /** diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/partial_transport_stream_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/partial_transport_stream_descriptor.h index c8ba441..6e3aa96 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/partial_transport_stream_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/partial_transport_stream_descriptor.h @@ -41,7 +41,7 @@ struct dvb_partial_transport_stream_descriptor { uint64_t reserved_2 : 2; , uint64_t minimum_overall_smoothing_rate :22; , uint64_t reserved_3 : 2; , - uint64_t maximum_overall_smoothing_rate :14; ) + uint64_t maximum_overall_smoothing_rate :14; ); } __ucsi_packed; /** diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/pdc_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/pdc_descriptor.h index 49cc187..68190be 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/pdc_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/pdc_descriptor.h @@ -37,7 +37,7 @@ struct dvb_pdc_descriptor { struct descriptor d; EBIT2(uint32_t reserved : 4; , - uint32_t programme_id_label :20; ) + uint32_t programme_id_label :20; ); } __ucsi_packed; /** diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rar_over_dvb_stream_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rar_over_dvb_stream_descriptor.h index b67b0d9..ba42d12 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rar_over_dvb_stream_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rar_over_dvb_stream_descriptor.h @@ -40,7 +40,7 @@ struct dvb_rnt_rar_over_dvb_stream_descriptor { dvbdate_t last_valid_date; EBIT3(uint8_t weighting : 6; , uint8_t complete_flag : 1; , - uint8_t scheduled_flag : 1; ) + uint8_t scheduled_flag : 1; ); uint16_t transport_stream_id; uint16_t original_network_id; uint16_t service_id; diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rar_over_ip_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rar_over_ip_descriptor.h index cc0ed58..b1f2da4 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rar_over_ip_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rar_over_ip_descriptor.h @@ -40,7 +40,7 @@ struct dvb_rnt_rar_over_ip_descriptor { dvbdate_t last_valid_date; EBIT3(uint8_t weighting : 6; , uint8_t complete_flag : 1; , - uint8_t reserved : 1; ) + uint8_t reserved : 1; ); uint8_t url_length; /* uint8_t url[] */ } __ucsi_packed; diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/rst_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/rst_section.c index 67fa0d3..259d2b0 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/rst_section.c +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/rst_section.c @@ -24,8 +24,8 @@ struct dvb_rst_section * dvb_rst_section_codec(struct section *section) { uint8_t * buf = (uint8_t *) section; - int pos = sizeof(struct section); - int len = section_length(section); + size_t pos = sizeof(struct section); + size_t len = section_length(section); struct dvb_rst_section * ret = (struct dvb_rst_section *) section; while (pos < len) { diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/rst_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/rst_section.h index b4269b8..4b3360b 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/rst_section.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/rst_section.h @@ -82,7 +82,7 @@ struct dvb_rst_section *dvb_rst_section_codec(struct section *section); static inline struct dvb_rst_status * dvb_rst_section_statuses_first(struct dvb_rst_section *rst) { - int pos = sizeof(struct dvb_rst_section); + size_t pos = sizeof(struct dvb_rst_section); if (pos >= section_length(&rst->head)) return NULL; @@ -108,4 +108,3 @@ static inline struct dvb_rst_status * #endif #endif - diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/s2_satellite_delivery_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/s2_satellite_delivery_descriptor.h index 66c9288..8f9fea8 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/s2_satellite_delivery_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/s2_satellite_delivery_descriptor.h @@ -39,7 +39,7 @@ struct dvb_s2_satellite_delivery_descriptor { EBIT4(uint8_t scrambling_sequence_selector : 1; , uint8_t multiple_input_stream : 1; , uint8_t backwards_compatability : 1; , - uint8_t reserved : 5; ) + uint8_t reserved : 5; ); /* uint32_t scrambling_sequence_index if scrambling_sequence_selector = 1 */ /* uint8_t input_stream_id if multiple_input_stream = 1 */ } __ucsi_packed; diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/satellite_delivery_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/satellite_delivery_descriptor.h index 23be76e..b93d052 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/satellite_delivery_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/satellite_delivery_descriptor.h @@ -42,9 +42,9 @@ struct dvb_satellite_delivery_descriptor { uint8_t polarization : 2; , uint8_t roll_off : 2; , uint8_t modulation_system : 1; , - uint8_t modulation_type : 2; ) + uint8_t modulation_type : 2; ); EBIT2(uint32_t symbol_rate : 28; , // BCD, units 100Hz - uint32_t fec_inner : 4; ) + uint32_t fec_inner : 4; ); } __ucsi_packed; /** diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/sdt_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/sdt_section.c index bdc8ce1..4c7824c 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/sdt_section.c +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/sdt_section.c @@ -24,8 +24,8 @@ struct dvb_sdt_section * dvb_sdt_section_codec(struct section_ext * ext) { uint8_t * buf = (uint8_t *) ext; - unsigned int pos = sizeof(struct section_ext); - unsigned int len = section_ext_length(ext); + size_t pos = sizeof(struct section_ext); + size_t len = section_ext_length(ext); if (len < sizeof(struct dvb_sdt_section)) return NULL; diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/sdt_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/sdt_section.h index 0130fe7..03a8569 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/sdt_section.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/sdt_section.h @@ -109,7 +109,7 @@ static inline uint16_t dvb_sdt_section_transport_stream_id(struct dvb_sdt_sectio static inline struct dvb_sdt_service * dvb_sdt_section_services_first(struct dvb_sdt_section * sdt) { - int pos = sizeof(struct dvb_sdt_section); + size_t pos = sizeof(struct dvb_sdt_section); if (pos >= section_ext_length(&sdt->head)) return NULL; diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/section.h index 8488d71..70e0880 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/section.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/section.h @@ -39,6 +39,7 @@ extern "C" #include <libucsi/dvb/tot_section.h> #include <libucsi/dvb/tva_container_section.h> #include <libucsi/dvb/int_section.h> +#include <libucsi/dvb/mpe_fec_section.h> /** * The following are not implemented just now. diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/service_availability_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/service_availability_descriptor.h index f16781b..64def75 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/service_availability_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/service_availability_descriptor.h @@ -37,7 +37,7 @@ struct dvb_service_availability_descriptor { struct descriptor d; EBIT2(uint8_t availability_flag : 1; , - uint8_t reserved : 7; ) + uint8_t reserved : 7; ); /* uint16_t cell_ids[] */ } __ucsi_packed; @@ -73,10 +73,10 @@ static inline struct dvb_service_availability_descriptor* * @param d dvb_service_availability_descriptor pointer. * @return Pointer to the field. */ -static inline uint32_t * +static inline uint16_t * dvb_service_availability_descriptor_cell_ids(struct dvb_service_availability_descriptor *d) { - return (uint32_t *) ((uint8_t *) d + sizeof(struct dvb_service_availability_descriptor)); + return (uint16_t *) ((uint8_t *) d + sizeof(struct dvb_service_availability_descriptor)); } /** diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/service_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/service_descriptor.h index e116ffc..dd0f0ec 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/service_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/service_descriptor.h @@ -49,7 +49,14 @@ enum { DVB_SERVICE_TYPE_EN50221 = 0x0d, DVB_SERVICE_TYPE_RCS_MAP = 0x0e, DVB_SERVICE_TYPE_RCS_FLS = 0x0f, - DVB_SERVICE_TYPE_MHP = 0x10 + DVB_SERVICE_TYPE_MHP = 0x10, + DVB_SERVICE_TYPE_MPEG2_HD_DIGITAL_TV = 0x11, + DVB_SERVICE_TYPE_ADVANCED_CODEC_SD_DIGITAL_TV = 0x16, + DVB_SERVICE_TYPE_ADVANCED_CODEC_SD_NVOD_TIMESHIFT = 0x17, + DVB_SERVICE_TYPE_ADVANCED_CODEC_SD_NVOD_REF = 0x18, + DVB_SERVICE_TYPE_ADVANCED_CODEC_HD_DIGITAL_TV = 0x19, + DVB_SERVICE_TYPE_ADVANCED_CODEC_HD_NVOD_TIMESHIFT = 0x1a, + DVB_SERVICE_TYPE_ADVANCED_CODEC_HD_NVOD_REF = 0x1b, }; /** diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/short_smoothing_buffer_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/short_smoothing_buffer_descriptor.h index 7deab9b..e52d20a 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/short_smoothing_buffer_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/short_smoothing_buffer_descriptor.h @@ -37,7 +37,7 @@ struct dvb_short_smoothing_buffer_descriptor { struct descriptor d; EBIT2(uint8_t sb_size : 2; , - uint8_t sb_leak_rate : 6; ) + uint8_t sb_leak_rate : 6; ); /* uint8_t reserved [] */ } __ucsi_packed; diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/sit_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/sit_section.c index 61134d0..06c228c 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/sit_section.c +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/sit_section.c @@ -25,8 +25,8 @@ struct dvb_sit_section * dvb_sit_section_codec(struct section_ext * ext) { uint8_t * buf = (uint8_t *) ext; struct dvb_sit_section * ret = (struct dvb_sit_section *) ext; - unsigned int pos = sizeof(struct section_ext); - unsigned int len = section_ext_length(ext); + size_t pos = sizeof(struct section_ext); + size_t len = section_ext_length(ext); if (len < sizeof(struct dvb_sit_section)) return NULL; @@ -67,4 +67,3 @@ struct dvb_sit_section * dvb_sit_section_codec(struct section_ext * ext) return ret; } - diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/sit_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/sit_section.h index d05989f..e06d596 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/sit_section.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/sit_section.h @@ -125,7 +125,7 @@ static inline struct descriptor * static inline struct dvb_sit_service * dvb_sit_section_services_first(struct dvb_sit_section *sit) { - int pos = sizeof(struct dvb_sit_section) + sit->transmission_info_loop_length; + size_t pos = sizeof(struct dvb_sit_section) + sit->transmission_info_loop_length; if (pos >= section_ext_length(&sit->head)) return NULL; diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/target_ip_address_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/target_ip_address_descriptor.h new file mode 100644 index 0000000..c08b60e --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/target_ip_address_descriptor.h @@ -0,0 +1,116 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * Copyright (C) 2006 Stephane Este-Gracias (sestegra@free.fr) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_TARGET_IP_ADDRESS_DESCRIPTOR +#define _UCSI_DVB_TARGET_IP_ADDRESS_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/types.h> + +/** + * dvb_target_ip_address_descriptor structure. + */ +struct dvb_target_ip_address_descriptor { + struct descriptor d; + + uint8_t ipv4_addr_mask[4]; + /* struct dvb_ipv4_addr ipv4_addr[] */ +} __ucsi_packed; + +/** + * An entry in the ipv4_addr field of a dvb_target_ip_address_descriptor. + */ +struct dvb_ipv4_addr { + uint8_t ipv4_addr[4]; +} __ucsi_packed; + +/** + * Process a dvb_target_ip_address_descriptor. + * + * @param d Generic descriptor structure pointer. + * @return dvb_target_ip_address_descriptor pointer, or NULL on error. + */ +static inline struct dvb_target_ip_address_descriptor* + dvb_target_ip_address_descriptor_codec(struct descriptor* d) +{ + uint32_t len = d->len - 4; + + if (len % sizeof(struct dvb_ipv4_addr)) + return NULL; + + return (struct dvb_target_ip_address_descriptor*) d; +} + +/** + * Iterator for entries in the ipv4_addr field of a dvb_target_ip_address_descriptor. + * + * @param d dvb_target_ip_address_descriptor pointer. + * @param pos Variable containing a pointer to the current dvb_ipv4_addr. + */ +#define dvb_target_ip_address_descriptor_ipv4_addr_for_each(d, pos) \ + for ((pos) = dvb_target_ip_address_descriptor_ipv4_addr_first(d); \ + (pos); \ + (pos) = dvb_target_ip_address_descriptor_ipv4_addr_next(d, pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_ipv4_addr* + dvb_target_ip_address_descriptor_ipv4_addr_first(struct dvb_target_ip_address_descriptor *d) +{ + if (d->d.len == 4) + return NULL; + + return (struct dvb_ipv4_addr *) + ((uint8_t*) d + sizeof(struct dvb_target_ip_address_descriptor)); +} + +static inline struct dvb_ipv4_addr* + dvb_target_ip_address_descriptor_ipv4_addr_next(struct dvb_target_ip_address_descriptor *d, + struct dvb_ipv4_addr *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len - 4; + uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_ipv4_addr); + + if (next >= end) + return NULL; + + return (struct dvb_ipv4_addr *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/target_ip_slash_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/target_ip_slash_descriptor.h new file mode 100644 index 0000000..e5bc76a --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/target_ip_slash_descriptor.h @@ -0,0 +1,116 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * Copyright (C) 2006 Stephane Este-Gracias (sestegra@free.fr) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_TARGET_IP_SLASH_DESCRIPTOR +#define _UCSI_DVB_TARGET_IP_SLASH_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/types.h> + +/** + * dvb_target_ip_slash_descriptor structure. + */ +struct dvb_target_ip_slash_descriptor { + struct descriptor d; + + /* struct dvb_ipv4_slash ipv4_slash[] */ +} __ucsi_packed; + +/** + * An entry in the ipv4_slash field of a dvb_target_ip_slash_descriptor. + */ +struct dvb_ipv4_slash { + uint8_t ipv4_addr[4]; + uint8_t ipv4_slash; +} __ucsi_packed; + +/** + * Process a dvb_target_ip_slash_descriptor. + * + * @param d Generic descriptor structure pointer. + * @return dvb_target_ip_slash_descriptor pointer, or NULL on error. + */ +static inline struct dvb_target_ip_slash_descriptor* + dvb_target_ip_slash_descriptor_codec(struct descriptor* d) +{ + uint32_t len = d->len; + + if (len % sizeof(struct dvb_ipv4_slash)) + return NULL; + + return (struct dvb_target_ip_slash_descriptor*) d; +} + +/** + * Iterator for entries in the ipv4_slash field of a dvb_target_ip_slash_descriptor. + * + * @param d dvb_target_ip_slash_descriptor pointer. + * @param pos Variable containing a pointer to the current dvb_ipv4_slash. + */ +#define dvb_target_ip_slash_descriptor_ipv4_slash_for_each(d, pos) \ + for ((pos) = dvb_target_ip_slash_descriptor_ipv4_slash_first(d); \ + (pos); \ + (pos) = dvb_target_ip_slash_descriptor_ipv4_slash_next(d, pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_ipv4_slash* + dvb_target_ip_slash_descriptor_ipv4_slash_first(struct dvb_target_ip_slash_descriptor *d) +{ + if (d->d.len == 0) + return NULL; + + return (struct dvb_ipv4_slash *) + ((uint8_t*) d + sizeof(struct dvb_target_ip_slash_descriptor)); +} + +static inline struct dvb_ipv4_slash* + dvb_target_ip_slash_descriptor_ipv4_slash_next(struct dvb_target_ip_slash_descriptor *d, + struct dvb_ipv4_slash *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_ipv4_slash); + + if (next >= end) + return NULL; + + return (struct dvb_ipv4_slash *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/target_ip_source_slash_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/target_ip_source_slash_descriptor.h new file mode 100644 index 0000000..8cade48 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/target_ip_source_slash_descriptor.h @@ -0,0 +1,118 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * Copyright (C) 2006 Stephane Este-Gracias (sestegra@free.fr) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_TARGET_IP_SOURCE_SLASH_DESCRIPTOR +#define _UCSI_DVB_TARGET_IP_SOURCE_SLASH_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/types.h> + +/** + * dvb_target_ip_source_slash_descriptor structure. + */ +struct dvb_target_ip_source_slash_descriptor { + struct descriptor d; + + /* struct dvb_ipv4_source_slash ipv4_source_slash[] */ +} __ucsi_packed; + +/** + * An entry in the ipv4_source_slash field of a dvb_target_ip_source_slash_descriptor. + */ +struct dvb_ipv4_source_slash { + uint8_t ipv4_source_addr[4]; + uint8_t ipv4_source_slash; + uint8_t ipv4_dest_addr[4]; + uint8_t ipv4_dest_slash; +} __ucsi_packed; + +/** + * Process a dvb_target_ip_source_slash_descriptor. + * + * @param d Generic descriptor structure pointer. + * @return dvb_target_ip_source_slash_descriptor pointer, or NULL on error. + */ +static inline struct dvb_target_ip_source_slash_descriptor* + dvb_target_ip_source_slash_descriptor_codec(struct descriptor* d) +{ + uint32_t len = d->len; + + if (len % sizeof(struct dvb_ipv4_source_slash)) + return NULL; + + return (struct dvb_target_ip_source_slash_descriptor*) d; +} + +/** + * Iterator for entries in the ipv4_source_slash field of a dvb_target_ip_source_slash_descriptor. + * + * @param d dvb_target_ip_source_slash_descriptor pointer. + * @param pos Variable containing a pointer to the current dvb_ipv4_source_slash. + */ +#define dvb_target_ip_source_slash_descriptor_ipv4_source_slash_for_each(d, pos) \ + for ((pos) = dvb_target_ip_source_slash_descriptor_ipv4_source_slash_first(d); \ + (pos); \ + (pos) = dvb_target_ip_source_slash_descriptor_ipv4_source_slash_next(d, pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_ipv4_source_slash* + dvb_target_ip_source_slash_descriptor_ipv4_source_slash_first(struct dvb_target_ip_source_slash_descriptor *d) +{ + if (d->d.len == 0) + return NULL; + + return (struct dvb_ipv4_source_slash *) + ((uint8_t*) d + sizeof(struct dvb_target_ip_source_slash_descriptor)); +} + +static inline struct dvb_ipv4_source_slash* + dvb_target_ip_source_slash_descriptor_ipv4_source_slash_next(struct dvb_target_ip_source_slash_descriptor *d, + struct dvb_ipv4_source_slash *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_ipv4_source_slash); + + if (next >= end) + return NULL; + + return (struct dvb_ipv4_source_slash *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/target_ipv6_address_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/target_ipv6_address_descriptor.h new file mode 100644 index 0000000..1b28b48 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/target_ipv6_address_descriptor.h @@ -0,0 +1,116 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * Copyright (C) 2006 Stephane Este-Gracias (sestegra@free.fr) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_TARGET_IPV6_ADDRESS_DESCRIPTOR +#define _UCSI_DVB_TARGET_IPV6_ADDRESS_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/types.h> + +/** + * dvb_target_ipv6_address_descriptor structure. + */ +struct dvb_target_ipv6_address_descriptor { + struct descriptor d; + + uint8_t ipv6_addr_mask[16]; + /* struct dvb_ipv6_addr ipv6_addr[] */ +} __ucsi_packed; + +/** + * An entry in the ipv6_addr field of a dvb_target_ipv6_address_descriptor. + */ +struct dvb_ipv6_addr { + uint8_t ipv6_addr[16]; +} __ucsi_packed; + +/** + * Process a dvb_target_ipv6_address_descriptor. + * + * @param d Generic descriptor structure pointer. + * @return dvb_target_ipv6_address_descriptor pointer, or NULL on error. + */ +static inline struct dvb_target_ipv6_address_descriptor* + dvb_target_ipv6_address_descriptor_codec(struct descriptor* d) +{ + uint32_t len = d->len - 16; + + if (len % sizeof(struct dvb_ipv6_addr)) + return NULL; + + return (struct dvb_target_ipv6_address_descriptor*) d; +} + +/** + * Iterator for entries in the ipv6_addr field of a dvb_target_ipv6_address_descriptor. + * + * @param d dvb_target_ipv6_address_descriptor pointer. + * @param pos Variable containing a pointer to the current dvb_ipv6_addr. + */ +#define dvb_target_ipv6_address_descriptor_ipv6_addr_for_each(d, pos) \ + for ((pos) = dvb_target_ipv6_address_descriptor_ipv6_addr_first(d); \ + (pos); \ + (pos) = dvb_target_ipv6_address_descriptor_ipv6_addr_next(d, pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_ipv6_addr* + dvb_target_ipv6_address_descriptor_ipv6_addr_first(struct dvb_target_ipv6_address_descriptor *d) +{ + if (d->d.len == 16) + return NULL; + + return (struct dvb_ipv6_addr *) + ((uint8_t*) d + sizeof(struct dvb_target_ipv6_address_descriptor)); +} + +static inline struct dvb_ipv6_addr* + dvb_target_ipv6_address_descriptor_ipv6_addr_next(struct dvb_target_ipv6_address_descriptor *d, + struct dvb_ipv6_addr *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len - 16; + uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_ipv6_addr); + + if (next >= end) + return NULL; + + return (struct dvb_ipv6_addr *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/target_ipv6_slash_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/target_ipv6_slash_descriptor.h new file mode 100644 index 0000000..3dc6d75 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/target_ipv6_slash_descriptor.h @@ -0,0 +1,116 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * Copyright (C) 2006 Stephane Este-Gracias (sestegra@free.fr) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_TARGET_IPV6_SLASH_DESCRIPTOR +#define _UCSI_DVB_TARGET_IPV6_SLASH_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/types.h> + +/** + * dvb_target_ipv6_slash_descriptor structure. + */ +struct dvb_target_ipv6_slash_descriptor { + struct descriptor d; + + /* struct dvb_ipv6_slash ipv6_slash[] */ +} __ucsi_packed; + +/** + * An entry in the ipv6_slash field of a dvb_target_ipv6_slash_descriptor. + */ +struct dvb_ipv6_slash { + uint8_t ipv6_addr[16]; + uint8_t ipv6_slash; +} __ucsi_packed; + +/** + * Process a dvb_target_ipv6_slash_descriptor. + * + * @param d Generic descriptor structure pointer. + * @return dvb_target_ipv6_slash_descriptor pointer, or NULL on error. + */ +static inline struct dvb_target_ipv6_slash_descriptor* + dvb_target_ipv6_slash_descriptor_codec(struct descriptor* d) +{ + uint32_t len = d->len; + + if (len % sizeof(struct dvb_ipv6_slash)) + return NULL; + + return (struct dvb_target_ipv6_slash_descriptor*) d; +} + +/** + * Iterator for entries in the ipv6_slash field of a dvb_target_ipv6_slash_descriptor. + * + * @param d dvb_target_ipv6_slash_descriptor pointer. + * @param pos Variable containing a pointer to the current dvb_ipv6_slash. + */ +#define dvb_target_ipv6_slash_descriptor_ipv6_slash_for_each(d, pos) \ + for ((pos) = dvb_target_ipv6_slash_descriptor_ipv6_slash_first(d); \ + (pos); \ + (pos) = dvb_target_ipv6_slash_descriptor_ipv6_slash_next(d, pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_ipv6_slash* + dvb_target_ipv6_slash_descriptor_ipv6_slash_first(struct dvb_target_ipv6_slash_descriptor *d) +{ + if (d->d.len == 0) + return NULL; + + return (struct dvb_ipv6_slash *) + ((uint8_t*) d + sizeof(struct dvb_target_ipv6_slash_descriptor)); +} + +static inline struct dvb_ipv6_slash* + dvb_target_ipv6_slash_descriptor_ipv6_slash_next(struct dvb_target_ipv6_slash_descriptor *d, + struct dvb_ipv6_slash *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_ipv6_slash); + + if (next >= end) + return NULL; + + return (struct dvb_ipv6_slash *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/target_ipv6_source_slash_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/target_ipv6_source_slash_descriptor.h new file mode 100644 index 0000000..3a4b38e --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/target_ipv6_source_slash_descriptor.h @@ -0,0 +1,118 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * Copyright (C) 2006 Stephane Este-Gracias (sestegra@free.fr) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_TARGET_IPV6_SOURCE_SLASH_DESCRIPTOR +#define _UCSI_DVB_TARGET_IPV6_SOURCE_SLASH_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/types.h> + +/** + * dvb_target_ipv6_source_slash_descriptor structure. + */ +struct dvb_target_ipv6_source_slash_descriptor { + struct descriptor d; + + /* struct dvb_ipv6_source_slash ipv6_source_slash[] */ +} __ucsi_packed; + +/** + * An entry in the ipv6_source_slash field of a dvb_target_ipv6_source_slash_descriptor. + */ +struct dvb_ipv6_source_slash { + uint8_t ipv6_source_addr[16]; + uint8_t ipv6_source_slash; + uint8_t ipv6_dest_addr[16]; + uint8_t ipv6_dest_slash; +} __ucsi_packed; + +/** + * Process a dvb_target_ipv6_source_slash_descriptor. + * + * @param d Generic descriptor structure pointer. + * @return dvb_target_ipv6_source_slash_descriptor pointer, or NULL on error. + */ +static inline struct dvb_target_ipv6_source_slash_descriptor* + dvb_target_ipv6_source_slash_descriptor_codec(struct descriptor* d) +{ + uint32_t len = d->len; + + if (len % sizeof(struct dvb_ipv6_source_slash)) + return NULL; + + return (struct dvb_target_ipv6_source_slash_descriptor*) d; +} + +/** + * Iterator for entries in the ipv6_source_slash field of a dvb_target_ipv6_source_slash_descriptor. + * + * @param d dvb_target_ipv6_source_slash_descriptor pointer. + * @param pos Variable containing a pointer to the current dvb_ipv6_source_slash. + */ +#define dvb_target_ipv6_source_slash_descriptor_ipv6_source_slash_for_each(d, pos) \ + for ((pos) = dvb_target_ipv6_source_slash_descriptor_ipv6_source_slash_first(d); \ + (pos); \ + (pos) = dvb_target_ipv6_source_slash_descriptor_ipv6_source_slash_next(d, pos)) + + + + + + + + + + +/******************************** PRIVATE CODE ********************************/ +static inline struct dvb_ipv6_source_slash* + dvb_target_ipv6_source_slash_descriptor_ipv6_source_slash_first(struct dvb_target_ipv6_source_slash_descriptor *d) +{ + if (d->d.len == 0) + return NULL; + + return (struct dvb_ipv6_source_slash *) + ((uint8_t*) d + sizeof(struct dvb_target_ipv6_source_slash_descriptor)); +} + +static inline struct dvb_ipv6_source_slash* + dvb_target_ipv6_source_slash_descriptor_ipv6_source_slash_next(struct dvb_target_ipv6_source_slash_descriptor *d, + struct dvb_ipv6_source_slash *pos) +{ + uint8_t *end = (uint8_t*) d + 2 + d->d.len; + uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_ipv6_source_slash); + + if (next >= end) + return NULL; + + return (struct dvb_ipv6_source_slash *) next; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/tdt_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/tdt_section.c index 30a23cf..ba64fe9 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/tdt_section.c +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/tdt_section.c @@ -23,7 +23,7 @@ struct dvb_tdt_section * dvb_tdt_section_codec(struct section * section) { - int len = section->length + sizeof(struct section); + size_t len = section_length(section); struct dvb_tdt_section * ret = (struct dvb_tdt_section *) section; if (len != sizeof(struct dvb_tdt_section)) diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/telephone_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/telephone_descriptor.h index 46b39e4..3dc43a1 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/telephone_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/telephone_descriptor.h @@ -38,14 +38,14 @@ struct dvb_telephone_descriptor { EBIT3(uint8_t reserved_1 : 2; , uint8_t foreign_availability : 1; , - uint8_t connection_type : 5; ) + uint8_t connection_type : 5; ); EBIT4(uint8_t reserved_2 : 1; , uint8_t country_prefix_length : 2; , uint8_t international_area_code_length : 3; , - uint8_t operator_code_length : 2; ) + uint8_t operator_code_length : 2; ); EBIT3(uint8_t reserved_3 : 1; , uint8_t national_area_code_length : 3; , - uint8_t core_number_length : 4; ) + uint8_t core_number_length : 4; ); /* uint8_t country_prefix[] */ /* uint8_t international_area_code[] */ /* uint8_t operator_code[] */ diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/teletext_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/teletext_descriptor.h index 280b6eb..424c1cb 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/teletext_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/teletext_descriptor.h @@ -39,7 +39,7 @@ enum { DVB_TELETEXT_TYPE_SUBTITLE = 0x02, DVB_TELETEXT_TYPE_ADDITIONAL = 0x03, DVB_TELETEXT_TYPE_SCHEDULE = 0x04, - DVB_TELETEXT_TYPE_SUBTITLE_HEARING_IMPAIRED= 0x05 + DVB_TELETEXT_TYPE_SUBTITLE_HEARING_IMPAIRED= 0x05, }; /** @@ -57,7 +57,7 @@ struct dvb_teletext_descriptor { struct dvb_teletext_entry { iso639lang_t language_code; EBIT2(uint8_t type : 5; , - uint8_t magazine_number: 3; ) + uint8_t magazine_number: 3; ); uint8_t page_number; } __ucsi_packed; diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/terrestrial_delivery_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/terrestrial_delivery_descriptor.h index b890178..c624dab 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/terrestrial_delivery_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/terrestrial_delivery_descriptor.h @@ -41,14 +41,14 @@ struct dvb_terrestrial_delivery_descriptor { uint8_t priority : 1; , uint8_t time_slicing_indicator : 1; , uint8_t mpe_fec_indicator : 1; , - uint8_t reserved_1 : 2; ) + uint8_t reserved_1 : 2; ); EBIT3(uint8_t constellation : 2; , uint8_t hierarchy_information : 3; , - uint8_t code_rate_hp_stream : 3; ) + uint8_t code_rate_hp_stream : 3; ); EBIT4(uint8_t code_rate_lp_stream : 3; , uint8_t guard_interval : 2; , uint8_t transmission_mode : 2; , - uint8_t other_frequency_flag : 1; ) + uint8_t other_frequency_flag : 1; ); uint32_t reserved_2; } __ucsi_packed; diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/time_slice_fec_identifier_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/time_slice_fec_identifier_descriptor.h new file mode 100644 index 0000000..00f3048 --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/time_slice_fec_identifier_descriptor.h @@ -0,0 +1,94 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * Copyright (C) 2008 Patrick Boettcher (pb@linuxtv.org) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_DVB_TIME_SLICE_FEC_IDENTIFIER_DESCRIPTOR +#define _UCSI_DVB_TIME_SLICE_FEC_IDENTIFIER_DESCRIPTOR 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/descriptor.h> +#include <libucsi/types.h> + +/* + * dvb_time_slice_fec_identifier_descriptor structure. + */ +struct dvb_time_slice_fec_identifier_descriptor { + struct descriptor d; + + EBIT4(uint8_t time_slicing :1; , + uint8_t mpe_fec :2; , + uint8_t reserved :2; , + uint8_t frame_size :3; ); + + uint8_t max_burst_duration; + + EBIT2(uint8_t max_average_rate :4; , + uint8_t time_slice_fec_id :4; ); + /* id_selector_bytes[] */ +}; + +static inline struct dvb_time_slice_fec_identifier_descriptor * + dvb_time_slice_fec_identifier_descriptor_codec(struct descriptor* d) +{ + if (d->len < 3) + return NULL; + return (struct dvb_time_slice_fec_identifier_descriptor *) d; +} + +static inline uint8_t dvb_time_slice_fec_identifier_selector_byte_length(struct dvb_time_slice_fec_identifier_descriptor *d) +{ + return d->d.len - 3; +} + +static inline uint8_t * dvb_time_slice_fec_identifier_selector_bytes(struct dvb_time_slice_fec_identifier_descriptor *d) +{ + if (d->d.len < 3) + return NULL; + else + return ((uint8_t *) d) + 2 + 3; +} + +static inline uint16_t dvb_time_slice_fec_identifier_max_burst_duration_msec(struct dvb_time_slice_fec_identifier_descriptor *d) +{ + return (d->max_burst_duration + 1) * 20; +} + +static inline uint16_t dvb_time_slice_fec_identifier_frame_size_kbits(struct dvb_time_slice_fec_identifier_descriptor *d) +{ + if (d->frame_size > 3) + return 0; + return (d->frame_size+1) * 512; +} + +static inline uint16_t dvb_time_slice_fec_identifier_frame_size_rows(struct dvb_time_slice_fec_identifier_descriptor *d) +{ + return dvb_time_slice_fec_identifier_frame_size_kbits(d) / 2; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/tot_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/tot_section.c index 3ce2c6d..5dc7890 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/tot_section.c +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/tot_section.c @@ -24,8 +24,8 @@ struct dvb_tot_section *dvb_tot_section_codec(struct section *section) { uint8_t * buf = (uint8_t *)section; - int pos = sizeof(struct section); - int len = section->length + sizeof(struct section) - CRC_SIZE; + size_t pos = sizeof(struct section); + size_t len = section_length(section) - CRC_SIZE; struct dvb_tot_section * ret = (struct dvb_tot_section *)section; if (len < sizeof(struct dvb_tot_section)) @@ -34,7 +34,7 @@ struct dvb_tot_section *dvb_tot_section_codec(struct section *section) pos += 5; bswap16(buf + pos); pos += 2; - + if ((pos + ret->descriptors_loop_length) > len) return NULL; diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_container_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_container_section.c index 32a5795..f526efc 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_container_section.c +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_container_section.c @@ -23,7 +23,7 @@ struct dvb_tva_container_section *dvb_tva_container_section_codec(struct section_ext *ext) { - int len = section_ext_length(ext); + size_t len = section_ext_length(ext); struct dvb_tva_container_section* ret = (struct dvb_tva_container_section*) ext; if (len < sizeof(struct dvb_tva_container_section)) diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_container_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_container_section.h index 6519ded..7d0abb1 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_container_section.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_container_section.h @@ -59,7 +59,7 @@ static inline uint16_t dvb_tva_container_section_container_id(struct dvb_tva_con } /** - * Accessor for the selector_byte field of a dvb_data_broadcast_id_descriptor. + * Accessor for the data field of a dvb_data_broadcast_id_descriptor. * * @param d dvb_data_broadcast_id_descriptor pointer. * @return Pointer to the field. diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_id_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_id_descriptor.h index c830259..3b4f3e8 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_id_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_id_descriptor.h @@ -45,7 +45,7 @@ struct dvb_tva_id_descriptor { struct dvb_tva_id_entry { uint16_t tva_id; EBIT2(uint8_t reserved : 5; , - uint8_t running_status : 3; ) + uint8_t running_status : 3; ); } __ucsi_packed; /** @@ -105,7 +105,7 @@ static inline struct dvb_tva_id_entry* } static inline struct dvb_tva_id_entry* - dvb_tva_id_descriptor_countries_next(struct dvb_tva_id_descriptor *d, + dvb_tva_id_descriptor_entries_next(struct dvb_tva_id_descriptor *d, struct dvb_tva_id_entry *pos) { uint8_t *end = (uint8_t*) d + 2 + d->d.len; diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/types.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/types.h index f26ea6b..437c7c3 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/types.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/types.h @@ -40,7 +40,7 @@ enum { DVB_RUNNING_STATUS_NOT_RUNNING = 0x01, DVB_RUNNING_STATUS_FEW_SECONDS = 0x02, DVB_RUNNING_STATUS_PAUSING = 0x03, - DVB_RUNNING_STATUS_RUNNING = 0x04 + DVB_RUNNING_STATUS_RUNNING = 0x04, }; /** diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/vbi_data_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/vbi_data_descriptor.h index 9d41e0c..b1d8703 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/vbi_data_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/vbi_data_descriptor.h @@ -39,7 +39,7 @@ enum { DVB_VBI_DATA_SERVICE_ID_VPS = 0x04, DVB_VBI_DATA_SERVICE_ID_WSS = 0x05, DVB_VBI_DATA_SERVICE_ID_CC = 0x06, - DVB_VBI_DATA_SERVICE_ID_MONO_422 = 0x07 + DVB_VBI_DATA_SERVICE_ID_MONO_422 = 0x07, }; /** @@ -66,7 +66,7 @@ struct dvb_vbi_data_entry { struct dvb_vbi_data_x { EBIT3(uint8_t reserved : 2; , uint8_t field_parity : 1; , - uint8_t line_offset : 5; ) + uint8_t line_offset : 5; ); } __ucsi_packed; /** diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/vbi_teletext_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/vbi_teletext_descriptor.h index 6ae9791..fd779d7 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/dvb/vbi_teletext_descriptor.h +++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/vbi_teletext_descriptor.h @@ -46,7 +46,7 @@ struct dvb_vbi_teletext_descriptor { struct dvb_vbi_teletext_entry { iso639lang_t language_code; EBIT2(uint8_t type : 5; , - uint8_t magazine_number: 3; ) + uint8_t magazine_number: 3; ); uint8_t page_number; } __ucsi_packed; diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/cat_section.c b/kaffeine/src/input/dvb/lib/libucsi/mpeg/cat_section.c index c72973e..8c974b8 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/mpeg/cat_section.c +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/cat_section.c @@ -24,7 +24,7 @@ struct mpeg_cat_section * mpeg_cat_section_codec(struct section_ext * ext) { uint8_t * buf = (uint8_t *)ext; - int pos = sizeof(struct section_ext); + size_t pos = sizeof(struct section_ext); if (verify_descriptors(buf + pos, section_ext_length(ext) - sizeof(struct mpeg_cat_section))) diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/cat_section.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/cat_section.h index 864b19e..7ed34a3 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/mpeg/cat_section.h +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/cat_section.h @@ -69,7 +69,7 @@ extern struct mpeg_cat_section *mpeg_cat_section_codec(struct section_ext *secti static inline struct descriptor * mpeg_cat_section_descriptors_first(struct mpeg_cat_section *cat) { - int pos = sizeof(struct mpeg_cat_section); + size_t pos = sizeof(struct mpeg_cat_section); if (pos >= section_ext_length(&cat->head)) return NULL; diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/datagram_section.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/datagram_section.h new file mode 100644 index 0000000..769773a --- /dev/null +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/datagram_section.h @@ -0,0 +1,81 @@ +/* + * section and descriptor parser + * + * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org) + * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net) + * Copyright (C) 2008 Patrick Boettcher (pb@linuxtv.org) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _UCSI_MPEG_DATAGRAM_SECTION_H +#define _UCSI_MPEG_DATAGRAM_SECTION_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <libucsi/section.h> + +/** + * datagram_section structure. + */ +struct datagram_section { + struct section head; + + uint8_t MAC_address_6; + uint8_t MAC_address_5; + EBIT5(uint8_t reserved : 2; , + uint8_t payload_scrambling_control : 2; , + uint8_t address_scrambling_control : 2; , + uint8_t LLC_SNAP_flag : 1; , + uint8_t current_next_indicator : 1; ); + uint8_t section_number; + uint8_t last_section_number; + uint8_t MAC_address_4; + uint8_t MAC_address_3; + uint8_t MAC_address_2; + uint8_t MAC_address_1; + + /* LLC_SNAP or IP-data */ + /* if last section stuffing */ + /* CRC */ +} __ucsi_packed; + +/** + */ +static inline struct datagram_section *datagram_section_codec(struct section *section) +{ + /* something to do here ? */ + return (struct datagram_section *) section; +} + +static inline uint8_t *datagram_section_ip_data(struct datagram_section *d) +{ + return (uint8_t *) d + sizeof(struct section) + 2 + 1 + 1 + 1 + 4; +} + +static inline size_t datagram_section_ip_data_length(struct datagram_section *d) +{ + return section_length(&d->head) - (sizeof(struct section) + 2 + 1 + 1 + 1 + 4) - CRC_SIZE; +} + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_section.c b/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_section.c index 9af1d96..c1ce019 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_section.c +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_section.c @@ -25,4 +25,3 @@ struct mpeg_metadata_section * mpeg_metadata_section_codec(struct section_ext * { return (struct mpeg_metadata_section *)ext; } - diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/odsmt_section.c b/kaffeine/src/input/dvb/lib/libucsi/mpeg/odsmt_section.c index c56ccb1..07407f2 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/mpeg/odsmt_section.c +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/odsmt_section.c @@ -25,8 +25,8 @@ struct mpeg_odsmt_section *mpeg_odsmt_section_codec(struct section_ext * ext) { struct mpeg_odsmt_section * odsmt = (struct mpeg_odsmt_section *)ext; uint8_t * buf = (uint8_t *)ext; - int pos = sizeof(struct section_ext); - int len = section_ext_length(ext); + size_t pos = sizeof(struct section_ext); + size_t len = section_ext_length(ext); int i; if (len < sizeof(struct mpeg_odsmt_section)) diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/odsmt_section.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/odsmt_section.h index 2e5302d..4e01085 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/mpeg/odsmt_section.h +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/odsmt_section.h @@ -61,9 +61,9 @@ struct mpeg_odsmt_stream_multi */ struct mpeg_odsmt_stream { union { - struct mpeg_odsmt_stream_single single __ucsi_packed; - struct mpeg_odsmt_stream_multi multi __ucsi_packed; - } u __ucsi_packed; + struct mpeg_odsmt_stream_single single; + struct mpeg_odsmt_stream_multi multi; + } u; } __ucsi_packed; /** @@ -118,7 +118,7 @@ static inline uint16_t mpeg_odsmt_section_pid(struct mpeg_odsmt_section *odsmt) */ static inline uint8_t* mpeg_odsmt_section_object_descriptors(struct mpeg_odsmt_section * odsmt, - uint32_t* len); + size_t* len); @@ -133,7 +133,7 @@ static inline uint8_t* static inline struct mpeg_odsmt_stream * mpeg_odsmt_section_streams_first(struct mpeg_odsmt_section *odsmt) { - int pos = sizeof(struct mpeg_odsmt_section); + size_t pos = sizeof(struct mpeg_odsmt_section); if (pos >= section_ext_length(&odsmt->head)) return NULL; @@ -144,12 +144,12 @@ static inline struct mpeg_odsmt_stream * static inline struct mpeg_odsmt_stream * mpeg_odsmt_section_streams_next(struct mpeg_odsmt_section *odsmt, struct mpeg_odsmt_stream *pos, - int index) + int _index) { uint8_t *end = (uint8_t*) odsmt + section_ext_length(&odsmt->head); uint8_t *next; - if (index > odsmt->stream_count) + if (_index > odsmt->stream_count) return NULL; next = (uint8_t *) pos + sizeof(struct mpeg_odsmt_stream_multi) + @@ -198,13 +198,13 @@ static inline struct descriptor * static inline uint8_t* mpeg_odsmt_section_object_descriptors(struct mpeg_odsmt_section * odsmt, - uint32_t* len) + size_t* len) { struct mpeg_odsmt_stream* pos; - int size = sizeof(struct mpeg_odsmt_section); - int index; + size_t size = sizeof(struct mpeg_odsmt_section); + int _index; - mpeg_odsmt_section_streams_for_each(odsmt, pos, index) { + mpeg_odsmt_section_streams_for_each(odsmt, pos, _index) { if (odsmt->stream_count == 0) size += sizeof(struct mpeg_odsmt_stream_single) + pos->u.single.es_info_length; diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/pat_section.c b/kaffeine/src/input/dvb/lib/libucsi/mpeg/pat_section.c index 80b28d5..2e4c2cc 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/mpeg/pat_section.c +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/pat_section.c @@ -24,8 +24,8 @@ struct mpeg_pat_section *mpeg_pat_section_codec(struct section_ext * ext) { uint8_t *buf = (uint8_t *)ext; - int pos = sizeof(struct section_ext); - int len = section_ext_length(ext); + size_t pos = sizeof(struct section_ext); + size_t len = section_ext_length(ext); if (len < sizeof(struct mpeg_pat_section)) return NULL; diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/pat_section.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/pat_section.h index 20b3f7a..eadfe28 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/mpeg/pat_section.h +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/pat_section.h @@ -44,7 +44,7 @@ struct mpeg_pat_section { struct mpeg_pat_program { uint16_t program_number; EBIT2(uint16_t reserved : 3; , - uint16_t pid :13; ) + uint16_t pid :13; ); } __ucsi_packed; /** @@ -90,7 +90,7 @@ static inline uint16_t mpeg_pat_section_transport_stream_id(struct mpeg_pat_sect static inline struct mpeg_pat_program * mpeg_pat_section_programs_first(struct mpeg_pat_section * pat) { - int pos = sizeof(struct mpeg_pat_section); + size_t pos = sizeof(struct mpeg_pat_section); if (pos >= section_ext_length(&pat->head)) return NULL; diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/pmt_section.c b/kaffeine/src/input/dvb/lib/libucsi/mpeg/pmt_section.c index 6ff4fac..e5aec6a 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/mpeg/pmt_section.c +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/pmt_section.c @@ -25,8 +25,8 @@ struct mpeg_pmt_section * mpeg_pmt_section_codec(struct section_ext * ext) { uint8_t * buf = (uint8_t *) ext; struct mpeg_pmt_section * pmt = (struct mpeg_pmt_section *) ext; - unsigned int pos = sizeof(struct section_ext); - unsigned int len = section_ext_length(ext); + size_t pos = sizeof(struct section_ext); + size_t len = section_ext_length(ext); if (len < sizeof(struct mpeg_pmt_section)) return NULL; diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/pmt_section.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/pmt_section.h index 73bba1d..03dea1b 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/mpeg/pmt_section.h +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/pmt_section.h @@ -36,9 +36,9 @@ struct mpeg_pmt_section { struct section_ext head; EBIT2(uint16_t reserved_1 : 3; , - uint16_t pcr_pid :13; ) + uint16_t pcr_pid :13; ); EBIT2(uint16_t reserved_2 : 4; , - uint16_t program_info_length :12; ) + uint16_t program_info_length :12; ); /* struct descriptor descriptors[] */ /* struct mpeg_pmt_stream streams[] */ } __ucsi_packed; @@ -49,9 +49,9 @@ struct mpeg_pmt_section { struct mpeg_pmt_stream { uint8_t stream_type; EBIT2(uint16_t reserved_1 : 3; , - uint16_t pid :13; ) + uint16_t pid :13; ); EBIT2(uint16_t reserved_2 : 4; , - uint16_t es_info_length :12; ) + uint16_t es_info_length :12; ); /* struct descriptor descriptors[] */ } __ucsi_packed; @@ -66,7 +66,7 @@ extern struct mpeg_pmt_section *mpeg_pmt_section_codec(struct section_ext *secti /** * Accessor for program_number field of a PMT. - * + * * @param pmt PMT pointer. * @return The program_number. */ @@ -140,7 +140,7 @@ static inline struct descriptor * static inline struct mpeg_pmt_stream * mpeg_pmt_section_streams_first(struct mpeg_pmt_section * pmt) { - int pos = sizeof(struct mpeg_pmt_section) + pmt->program_info_length; + size_t pos = sizeof(struct mpeg_pmt_section) + pmt->program_info_length; if (pos >= section_ext_length(&pmt->head)) return NULL; diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/section.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/section.h index 6215e95..f71f95e 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/mpeg/section.h +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/section.h @@ -33,6 +33,7 @@ extern "C" #include <libucsi/mpeg/pmt_section.h> #include <libucsi/mpeg/tsdt_section.h> #include <libucsi/mpeg/metadata_section.h> +#include <libucsi/mpeg/datagram_section.h> #define TRANSPORT_PAT_PID 0x00 #define TRANSPORT_CAT_PID 0x01 @@ -48,7 +49,8 @@ enum mpeg_section_tag { stag_mpeg_transport_stream_description = 0x03, stag_mpeg_iso14496_scene_description = 0x04, stag_mpeg_iso14496_object_description = 0x05, - stag_mpeg_metadata = 0x06 + stag_mpeg_metadata = 0x06, + stag_mpeg_datagram = 0x3e, }; #ifdef __cplusplus diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/tsdt_section.c b/kaffeine/src/input/dvb/lib/libucsi/mpeg/tsdt_section.c index fbbbe3c..fec9dd7 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/mpeg/tsdt_section.c +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/tsdt_section.c @@ -24,7 +24,7 @@ struct mpeg_tsdt_section * mpeg_tsdt_section_codec(struct section_ext * ext) { uint8_t * buf = (uint8_t *)ext; - int pos = sizeof(struct section_ext); + size_t pos = sizeof(struct section_ext); if (verify_descriptors(buf + pos, section_ext_length(ext) - sizeof(struct mpeg_tsdt_section))) @@ -32,4 +32,3 @@ struct mpeg_tsdt_section * mpeg_tsdt_section_codec(struct section_ext * ext) return (struct mpeg_tsdt_section *)ext; } - diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/tsdt_section.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/tsdt_section.h index 9039278..2bbae02 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/mpeg/tsdt_section.h +++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/tsdt_section.h @@ -70,7 +70,7 @@ extern struct mpeg_tsdt_section *mpeg_tsdt_section_codec(struct section_ext *sec static inline struct descriptor * mpeg_tsdt_section_descriptors_first(struct mpeg_tsdt_section * tsdt) { - int pos = sizeof(struct mpeg_tsdt_section); + size_t pos = sizeof(struct mpeg_tsdt_section); if (pos >= section_ext_length(&tsdt->head)) return NULL; diff --git a/kaffeine/src/input/dvb/lib/libucsi/section.h b/kaffeine/src/input/dvb/lib/libucsi/section.h index e2f7551..53ad07f 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/section.h +++ b/kaffeine/src/input/dvb/lib/libucsi/section.h @@ -43,7 +43,7 @@ struct section { EBIT4(uint16_t syntax_indicator : 1; , uint16_t private_indicator : 1; , /* 2.4.4.10 */ uint16_t reserved : 2; , - uint16_t length :12; ) + uint16_t length :12; ); } __ucsi_packed; /** @@ -54,12 +54,12 @@ struct section_ext { EBIT4(uint16_t syntax_indicator : 1; , uint16_t private_indicator : 1; , /* 2.4.4.10 */ uint16_t reserved : 2; , - uint16_t length :12; ) + uint16_t length :12; ); uint16_t table_id_ext; EBIT3(uint8_t reserved1 : 2; , uint8_t version_number : 5; , - uint8_t current_next_indicator : 1; ) + uint8_t current_next_indicator : 1; ); uint8_t section_number; uint8_t last_section_number; } __ucsi_packed; @@ -76,13 +76,36 @@ struct psi_table_state { /** + * Determine the total length of a section, including the header. + * + * @param section The parsed section structure. + * @return The length. + */ +static inline size_t section_length(struct section *section) +{ + return section->length + sizeof(struct section); +} + +/** + * Determine the total length of an extended section, including the header, + * but omitting the CRC. + * + * @param section The parsed section_ext structure. + * @return The length. + */ +static inline size_t section_ext_length(struct section_ext * section) +{ + return section->length + sizeof(struct section) - CRC_SIZE; +} + +/** * Process a section structure in-place. * * @param buf Pointer to the data. * @param len Length of data. * @return Pointer to the section structure, or NULL if invalid. */ -static inline struct section * section_codec(uint8_t * buf, int len) +static inline struct section * section_codec(uint8_t * buf, size_t len) { struct section * ret = (struct section *)buf; @@ -91,7 +114,7 @@ static inline struct section * section_codec(uint8_t * buf, int len) bswap16(buf+1); - if (len != ret->length + 3) + if (len != ret->length + 3U) return NULL; return ret; @@ -107,7 +130,7 @@ static inline struct section * section_codec(uint8_t * buf, int len) static inline int section_check_crc(struct section *section) { uint8_t * buf = (uint8_t *) section; - int len = sizeof(struct section) + section->length; + size_t len = section_length(section); uint32_t crc; /* the crc check has to be performed on the unswapped data */ @@ -167,12 +190,9 @@ static inline struct section_ext * section_ext_encode(struct section_ext* sectio int len = sizeof(struct section) + section->length; uint32_t crc; - /* zap the current CRC value */ - memset(buf+len-4, 0, 4); - /* the crc has to be performed on the swapped data */ bswap16(buf+1); - crc = crc32(CRC32_INIT, buf, len); + crc = crc32(CRC32_INIT, buf, len-4); bswap16(buf+1); /* update the CRC */ @@ -184,29 +204,6 @@ static inline struct section_ext * section_ext_encode(struct section_ext* sectio } /** - * Determine the total length of a section, including the header. - * - * @param section The parsed section structure. - * @return The length. - */ -static inline int section_length(struct section *section) -{ - return section->length + sizeof(struct section); -} - -/** - * Determine the total length of an extended section, including the header, - * but omitting the CRC. - * - * @param section The parsed section_ext structure. - * @return The length. - */ -static inline int section_ext_length(struct section_ext * section) -{ - return section->length + sizeof(struct section) - CRC_SIZE; -} - -/** * Reset a psi_table_state structure. * * @param tstate The structure to reset. @@ -227,7 +224,10 @@ static inline int section_ext_useful(struct section_ext *section, struct psi_tab { if ((section->version_number == tstate->version_number) && tstate->complete) return 0; - if ((section->version_number != tstate->version_number) && (section->section_number == 0)) { + if (section->version_number != tstate->version_number) { + if (section->section_number != 0) + return 0; + tstate->next_section_number = 0; tstate->complete = 0; tstate->version_number = section->version_number; diff --git a/kaffeine/src/input/dvb/lib/libucsi/section_buf.h b/kaffeine/src/input/dvb/lib/libucsi/section_buf.h index e15cc1d..52d2f84 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/section_buf.h +++ b/kaffeine/src/input/dvb/lib/libucsi/section_buf.h @@ -54,11 +54,10 @@ struct section_buf { extern int section_buf_init(struct section_buf *section, int max); /** - * Initialise a section_buf structure. + * Reset a section_buf structure (e.g. if a discontinuity occurred). The + * section_buf will wait for the first PDU start indicator. * - * @param section The section_buf to initialise. - * @param max Maximum number of bytes in section (must be > 3) - * @return 0 on success, nonzero on error. + * @param section The section_buf to reset. */ static inline void section_buf_reset(struct section_buf *section) { diff --git a/kaffeine/src/input/dvb/lib/libucsi/transport_packet.h b/kaffeine/src/input/dvb/lib/libucsi/transport_packet.h index 7dfbd78..6314eca 100644 --- a/kaffeine/src/input/dvb/lib/libucsi/transport_packet.h +++ b/kaffeine/src/input/dvb/lib/libucsi/transport_packet.h @@ -145,7 +145,7 @@ static inline int transport_packet_pid(struct transport_packet *pkt) /** * Process a buffer into a transport packet. * - * @param buf Raw buffer. + * @param buf Raw buffer. Note, this function assumes there are 188 bytes available. * @return transport_packet pointer, or NULL on error. */ static inline struct transport_packet *transport_packet_init(unsigned char *buf) diff --git a/kaffeine/src/input/dvb/plugins/epg/kaffeinedvbsection.cpp b/kaffeine/src/input/dvb/plugins/epg/kaffeinedvbsection.cpp index d6170e8..54c912e 100644 --- a/kaffeine/src/input/dvb/plugins/epg/kaffeinedvbsection.cpp +++ b/kaffeine/src/input/dvb/plugins/epg/kaffeinedvbsection.cpp @@ -141,6 +141,9 @@ bool KaffeineDVBsection::doIconv( QCString &s, QCString table, char *buffer, int if ( inSize<1 ) return false; cd = iconv_open( "UTF8", table ); + //check if charset unknown + if( cd == (iconv_t)(-1) ) + return false; inBuf = s.data(); outBuf = buffer; outBuf[0] = 0; diff --git a/kaffeine/src/input/dvb/scandialog.cpp b/kaffeine/src/input/dvb/scandialog.cpp index 2399c74..4e1a14c 100644 --- a/kaffeine/src/input/dvb/scandialog.cpp +++ b/kaffeine/src/input/dvb/scandialog.cpp @@ -109,13 +109,15 @@ ScanDialog::ScanDialog( QPtrList<DvbStream> *d, QPtrList<ChannelDesc> *ch, QSize foundList->clear(); foundList->setAllColumnsShowFocus( true ); foundList->setSelectionMode( QListView::Extended ); - channelsList->setSorting( 0 ); + channelsList->setSorting( 1 ); // sort by source 1st than channel name + channelsList->setAllColumnsShowFocus( true ); + channelsList->setSelectionMode( QListView::Extended ); ChannelDesc *chan; QListViewItem *it; for ( int i=0; i<(int)chandesc->count(); i++ ) { chan = chandesc->at(i); - it = new QListViewItem( channelsList, chan->name ); + it = new QListViewItem( channelsList, chan->name, chan->tp.source ); if ( !chan->pix.isNull() ) it->setPixmap( 0, chan->pix ); else { @@ -425,7 +427,11 @@ void ScanDialog::parseTp( QString s, fe_type_t type, QString src ) trans->type=FE_QAM; trans->source = "Cable"; } - else { + else if ( s.left(pos)=="A" ) { + trans->type=FE_ATSC; + trans->source = "ATSC Terrestrial"; + } + else if ( s.left(pos)=="S" ) { trans->type=FE_QPSK; trans->source = src; } @@ -439,14 +445,15 @@ void ScanDialog::parseTp( QString s, fe_type_t type, QString src ) trans->freq = s.left(pos).toULong()/1000; s = s.right( s.length()-pos-1 ); s = s.stripWhiteSpace(); - pos = s.find(" "); + if ( trans->type!=FE_ATSC ) + pos = s.find(" "); if ( trans->type==FE_QPSK ) { trans->pol = s.left(pos).lower()[0].latin1(); s = s.right( s.length()-pos-1 ); s = s.stripWhiteSpace(); pos = s.find(" "); } - if ( trans->type!=FE_OFDM ) { + if ( trans->type!=FE_OFDM && trans->type!=FE_ATSC ) { trans->sr = s.left(pos).toULong()/1000; } else { @@ -459,6 +466,27 @@ void ScanDialog::parseTp( QString s, fe_type_t type, QString src ) else trans->bandwidth = BANDWIDTH_AUTO; } + if ( trans->type==FE_ATSC ) { + if ( s.left(pos)=="8VSB" ) + trans->modulation = VSB_8; + else if ( s.left(pos)=="16VSB" ) + trans->modulation = VSB_16; + else if ( s.left(pos)=="QAM16" ) + trans->modulation = QAM_16; + else if ( s.left(pos)=="QAM32" ) + trans->modulation = QAM_32; + else if ( s.left(pos)=="QAM64" ) + trans->modulation = QAM_64; + else if ( s.left(pos)=="QAM128" ) + trans->modulation = QAM_128; + else if ( s.left(pos)=="QAM256" ) + trans->modulation = QAM_256; + else + trans->modulation = QAM_AUTO; + transponders.append( trans ); + return; + } + s = s.right( s.length()-pos-1 ); s = s.stripWhiteSpace(); pos = s.find(" "); @@ -584,7 +612,17 @@ bool ScanDialog::getTransData() if ( searchComb->currentText().startsWith("AUTO") ) { int i; - for ( i=402; i<900; i+=8 ) { + for ( i=177; i<227; i+=7 ) { + if ( offset07->isChecked() ) { + s = QString("T %1 7MHz AUTO AUTO AUTO AUTO AUTO AUTO").arg( (i*1000000)+500000 ); + parseTp( s, ds->getType(), "" ); + } + if ( offset125p->isChecked() ) { + s = QString("T %1 7MHz AUTO AUTO AUTO AUTO AUTO AUTO").arg( (i*1000000)+500000+125000 ); + parseTp( s, ds->getType(), "" ); + } + } + for ( i=474; i<859; i+=8 ) { if ( offset167m->isChecked() ) { s = QString("T %1 8MHz AUTO AUTO AUTO AUTO AUTO AUTO").arg( (i*1000000)-167000 ); parseTp( s, ds->getType(), "" ); @@ -605,7 +643,9 @@ bool ScanDialog::getTransData() case FE_QPSK : s += "dvb-s/"; break; case FE_QAM : s += "dvb-c/"; break; case FE_OFDM : s += "dvb-t/"; break; - case FE_ATSC : return false; + case FE_ATSC : s += "atsc/"; break; + default: + return false; } s += searchComb->currentText(); QFile f( s ); @@ -713,7 +753,9 @@ void ScanDialog::addSelected() if(checkChannUpdate(chan)){ checkDuplicateName( chan ); - chan->num = chandesc->count()+1; + if (chan->num == 0) { + chan->num = chandesc->count()+1; + } chandesc->append( new ChannelDesc( *chan ) ); it = new QListViewItem( channelsList, chan->name ); if ( chan->type==1 ) { diff --git a/kaffeine/src/input/dvb/scandialogui.ui b/kaffeine/src/input/dvb/scandialogui.ui index 04cbdd1..cdc1059 100644 --- a/kaffeine/src/input/dvb/scandialogui.ui +++ b/kaffeine/src/input/dvb/scandialogui.ui @@ -8,8 +8,8 @@ <rect> <x>0</x> <y>0</y> - <width>725</width> - <height>560</height> + <width>790</width> + <height>578</height> </rect> </property> <property name="caption"> @@ -21,7 +21,7 @@ </property> <widget class="QLayoutWidget" row="0" column="0"> <property name="name"> - <cstring>layout10</cstring> + <cstring>layout9</cstring> </property> <vbox> <property name="name"> @@ -29,7 +29,7 @@ </property> <widget class="QLayoutWidget"> <property name="name"> - <cstring>layout9</cstring> + <cstring>layout8</cstring> </property> <hbox> <property name="name"> @@ -66,9 +66,28 @@ <bool>true</bool> </property> </column> + <column> + <property name="text"> + <string>Source</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> <property name="name"> <cstring>channelsList</cstring> </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>3</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> <property name="rootIsDecorated"> <bool>false</bool> </property> @@ -123,38 +142,51 @@ <property name="title"> <string>Search On</string> </property> - <vbox> + <grid> <property name="name"> <cstring>unnamed</cstring> </property> - <widget class="QComboBox"> + <widget class="QComboBox" row="0" column="0"> <property name="name"> <cstring>searchComb</cstring> </property> </widget> - <widget class="QGroupBox"> + <widget class="QGroupBox" row="1" column="0"> <property name="name"> <cstring>offsetGroup</cstring> </property> <property name="title"> <string>Offset (KHz)</string> </property> - <hbox> + <grid> <property name="name"> <cstring>unnamed</cstring> </property> - <widget class="QCheckBox"> + <widget class="QCheckBox" row="1" column="3"> <property name="name"> - <cstring>offset0</cstring> + <cstring>offset167m</cstring> </property> <property name="text"> - <string>0</string> + <string>-167</string> </property> - <property name="checked"> - <bool>true</bool> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>(7MHz)</string> </property> </widget> - <widget class="QCheckBox"> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel1_2</cstring> + </property> + <property name="text"> + <string>(8MHz)</string> + </property> + </widget> + <widget class="QCheckBox" row="1" column="2"> <property name="name"> <cstring>offset167p</cstring> </property> @@ -162,17 +194,39 @@ <string>+167</string> </property> </widget> - <widget class="QCheckBox"> + <widget class="QCheckBox" row="0" column="2" rowspan="1" colspan="2"> <property name="name"> - <cstring>offset167m</cstring> + <cstring>offset125p</cstring> </property> <property name="text"> - <string>-167</string> + <string>+125</string> </property> </widget> - </hbox> + <widget class="QCheckBox" row="1" column="1"> + <property name="name"> + <cstring>offset0</cstring> + </property> + <property name="text"> + <string>0</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QCheckBox" row="0" column="1"> + <property name="name"> + <cstring>offset07</cstring> + </property> + <property name="text"> + <string>0</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </grid> </widget> - </vbox> + </grid> </widget> <widget class="QPushButton"> <property name="name"> @@ -206,7 +260,7 @@ <property name="sizeHint"> <size> <width>20</width> - <height>20</height> + <height>18</height> </size> </property> </spacer> @@ -231,210 +285,190 @@ <property name="sizeHint"> <size> <width>21</width> - <height>20</height> + <height>19</height> </size> </property> </spacer> - <widget class="QLayoutWidget"> + <widget class="QGroupBox"> <property name="name"> - <cstring>layout38</cstring> + <cstring>filtersGroup</cstring> + </property> + <property name="title"> + <string>Filters</string> </property> - <vbox> + <grid> <property name="name"> <cstring>unnamed</cstring> </property> - <widget class="QGroupBox"> + <widget class="QCheckBox" row="2" column="0"> <property name="name"> - <cstring>filtersGroup</cstring> + <cstring>radioCb</cstring> </property> - <property name="title"> - <string>Filters</string> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Radio</string> </property> - <grid> - <property name="name"> - <cstring>unnamed</cstring> - </property> - <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="2"> - <property name="name"> - <cstring>ftaCb</cstring> - </property> - <property name="sizePolicy"> - <sizepolicy> - <hsizetype>4</hsizetype> - <vsizetype>0</vsizetype> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Free to air</string> - </property> - </widget> - <widget class="QCheckBox" row="2" column="0" rowspan="1" colspan="2"> - <property name="name"> - <cstring>radioCb</cstring> - </property> - <property name="sizePolicy"> - <sizepolicy> - <hsizetype>4</hsizetype> - <vsizetype>0</vsizetype> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Radio</string> - </property> - </widget> - <widget class="QCheckBox" row="1" column="0" rowspan="1" colspan="2"> - <property name="name"> - <cstring>tvCb</cstring> - </property> - <property name="sizePolicy"> - <sizepolicy> - <hsizetype>4</hsizetype> - <vsizetype>0</vsizetype> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>TV</string> - </property> - </widget> - <widget class="QCheckBox" row="3" column="0"> - <property name="name"> - <cstring>providerCb</cstring> - </property> - <property name="sizePolicy"> - <sizepolicy> - <hsizetype>0</hsizetype> - <vsizetype>0</vsizetype> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Provider:</string> - </property> - </widget> - <widget class="QComboBox" row="3" column="1"> - <property name="name"> - <cstring>providerComb</cstring> - </property> - <property name="sizePolicy"> - <sizepolicy> - <hsizetype>3</hsizetype> - <vsizetype>0</vsizetype> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - </widget> - </grid> </widget> - <widget class="QPushButton"> + <widget class="QCheckBox" row="1" column="0"> <property name="name"> - <cstring>addselectedBtn</cstring> + <cstring>tvCb</cstring> </property> <property name="sizePolicy"> <sizepolicy> - <hsizetype>1</hsizetype> + <hsizetype>4</hsizetype> <vsizetype>0</vsizetype> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="text"> - <string><< Add Selected</string> + <string>TV</string> </property> </widget> - <widget class="QPushButton"> + <widget class="QCheckBox" row="3" column="0"> <property name="name"> - <cstring>addfilteredBtn</cstring> + <cstring>providerCb</cstring> </property> <property name="sizePolicy"> <sizepolicy> - <hsizetype>1</hsizetype> + <hsizetype>0</hsizetype> <vsizetype>0</vsizetype> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="text"> - <string><< Add Filtered</string> + <string>Provider:</string> </property> </widget> - </vbox> - </widget> - </vbox> - </widget> - <widget class="QGroupBox"> - <property name="name"> - <cstring>groupBox11</cstring> - </property> - <property name="title"> - <string>Found</string> - </property> - <vbox> - <property name="name"> - <cstring>unnamed</cstring> - </property> - <widget class="QLayoutWidget"> - <property name="name"> - <cstring>layout8</cstring> - </property> - <vbox> - <property name="name"> - <cstring>unnamed</cstring> - </property> - <widget class="QListView"> - <column> - <property name="text"> - <string>SNR</string> - </property> - <property name="clickable"> - <bool>true</bool> - </property> - <property name="resizable"> - <bool>true</bool> - </property> - </column> - <column> - <property name="text"> - <string>Name</string> - </property> - <property name="clickable"> - <bool>true</bool> - </property> - <property name="resizable"> - <bool>true</bool> - </property> - </column> + <widget class="QComboBox" row="3" column="1"> <property name="name"> - <cstring>foundList</cstring> + <cstring>providerComb</cstring> </property> <property name="sizePolicy"> <sizepolicy> - <hsizetype>7</hsizetype> - <vsizetype>3</vsizetype> + <hsizetype>3</hsizetype> + <vsizetype>0</vsizetype> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> </widget> - <widget class="QPushButton"> + <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="2"> <property name="name"> - <cstring>selectallBtn</cstring> + <cstring>ftaCb</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> </property> <property name="text"> - <string>Select All</string> + <string>Free to air</string> </property> </widget> - </vbox> + </grid> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>addselectedBtn</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string><< Add Selected</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>addfilteredBtn</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string><< Add Filtered</string> + </property> </widget> </vbox> </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox11</cstring> + </property> + <property name="title"> + <string>Found</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QListView" row="0" column="0"> + <column> + <property name="text"> + <string>SNR</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Name</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>foundList</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>3</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QPushButton" row="1" column="0"> + <property name="name"> + <cstring>selectallBtn</cstring> + </property> + <property name="text"> + <string>Select All</string> + </property> + </widget> + </grid> + </widget> </hbox> </widget> <widget class="Line"> diff --git a/kaffeine/src/input/dvb/ts2rtp.cpp b/kaffeine/src/input/dvb/ts2rtp.cpp index 9f87a84..4784122 100644 --- a/kaffeine/src/input/dvb/ts2rtp.cpp +++ b/kaffeine/src/input/dvb/ts2rtp.cpp @@ -345,7 +345,12 @@ void Ts2Rtp::psiTables( QPtrList<ChannelDesc> *channels ) buf[off++] = 0x01; // current_next_indicator buf[off++] = 0x00; // section_number buf[off++] = 0x00; // last_section_number - buf[off++] = desc->vpid>>8; buf[off++] = desc->vpid&0xff; // PCR pid + if ( desc->vpid ) { + buf[off++] = desc->vpid>>8; buf[off++] = desc->vpid&0xff; // PCR pid + } + else if ( desc->napid ) { + buf[off++] = desc->apid[0].pid>>8; buf[off++] = desc->apid[0].pid&0xff; // PCR pid + } buf[off++] = 0x00; buf[off++] = 0x00; // infos_length if ( desc->vpid ) { buf[off++] = desc->vType; // stream_type |