mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-22 16:08:39 -05:00
Merge pull request #826 from srcejon/datvmod_dvbs2
Add DVB-S2 modulator
This commit is contained in:
commit
688386e5ef
@ -9,6 +9,18 @@ set(moddatv_SOURCES
|
||||
datvmodsettings.cpp
|
||||
datvmodwebapiadapter.cpp
|
||||
dvb-s/dvb-s.cpp
|
||||
dvb-s2/DVB2.cpp
|
||||
dvb-s2/DVBS2.cpp
|
||||
dvb-s2/dvb2_bbheader.cpp
|
||||
dvb-s2/dvb2_bch.cpp
|
||||
dvb-s2/dvb2_ldpc_encode.cpp
|
||||
dvb-s2/dvb2_ldpc_tables.cpp
|
||||
dvb-s2/dvb2_scrambler.cpp
|
||||
dvb-s2/dvbs2_interleave.cpp
|
||||
dvb-s2/dvbs2_modulator.cpp
|
||||
dvb-s2/dvbs2_physical.cpp
|
||||
dvb-s2/dvbs2_scrambler.cpp
|
||||
dvb-s2/dvbs2_tables.cpp
|
||||
)
|
||||
|
||||
set(moddatv_HEADERS
|
||||
@ -20,6 +32,9 @@ set(moddatv_HEADERS
|
||||
datvmodsettings.h
|
||||
datvmodwebapiadapter.h
|
||||
dvb-s/dvb-s.h
|
||||
dvb-s/dvb-s.h
|
||||
dvb-s2/DVB2.h
|
||||
dvb-s2/DVBS2.h
|
||||
)
|
||||
|
||||
include_directories(
|
||||
|
@ -225,16 +225,59 @@ void DATVModGUI::on_deltaFrequency_changed(qint64 value)
|
||||
|
||||
void DATVModGUI::on_dvbStandard_currentIndexChanged(int index)
|
||||
{
|
||||
int idx;
|
||||
|
||||
m_settings.m_standard = (DATVModSettings::DVBStandard) index;
|
||||
|
||||
ui->fec->blockSignals(true);
|
||||
ui->rollOff->blockSignals(true);
|
||||
ui->modulation->blockSignals(true);
|
||||
|
||||
ui->fec->clear();
|
||||
ui->rollOff->clear();
|
||||
ui->modulation->clear();
|
||||
|
||||
if (m_settings.m_standard == DATVModSettings::DVB_S)
|
||||
{
|
||||
ui->rollOff->addItem("0.35");
|
||||
ui->modulation->addItem("BPSK");
|
||||
ui->modulation->addItem("QPSK");
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->rollOff->addItem("0.20");
|
||||
ui->rollOff->addItem("0.25");
|
||||
ui->rollOff->addItem("0.35");
|
||||
ui->modulation->addItem("QPSK");
|
||||
ui->modulation->addItem("8PSK");
|
||||
ui->modulation->addItem("16APSK");
|
||||
ui->modulation->addItem("32APSK");
|
||||
}
|
||||
|
||||
ui->rollOff->blockSignals(false);
|
||||
ui->modulation->blockSignals(false);
|
||||
|
||||
m_doApplySettings = false;
|
||||
|
||||
idx = ui->rollOff->findText(QString("%1").arg(m_settings.m_rollOff, 0, 'f', 2));
|
||||
idx = idx == -1 ? 0 : idx;
|
||||
ui->rollOff->setCurrentIndex(idx);
|
||||
on_rollOff_currentIndexChanged(idx);
|
||||
idx = ui->modulation->findText(DATVModSettings::mapModulation(m_settings.m_modulation));
|
||||
idx = idx == -1 ? 0 : idx;
|
||||
ui->modulation->setCurrentIndex(idx);
|
||||
on_modulation_currentIndexChanged(idx);
|
||||
|
||||
updateFEC();
|
||||
|
||||
m_doApplySettings = true;
|
||||
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void DATVModGUI::updateFEC()
|
||||
{
|
||||
ui->fec->blockSignals(true);
|
||||
|
||||
ui->fec->clear();
|
||||
if (m_settings.m_standard == DATVModSettings::DVB_S)
|
||||
{
|
||||
ui->fec->addItem("1/2");
|
||||
@ -242,11 +285,8 @@ void DATVModGUI::on_dvbStandard_currentIndexChanged(int index)
|
||||
ui->fec->addItem("3/4");
|
||||
ui->fec->addItem("5/6");
|
||||
ui->fec->addItem("7/8");
|
||||
ui->rollOff->addItem("0.35");
|
||||
ui->modulation->addItem("BPSK");
|
||||
ui->modulation->addItem("QPSK");
|
||||
}
|
||||
else
|
||||
else if (m_settings.m_modulation == DATVModSettings::QPSK)
|
||||
{
|
||||
ui->fec->addItem("1/4");
|
||||
ui->fec->addItem("1/3");
|
||||
@ -259,29 +299,51 @@ void DATVModGUI::on_dvbStandard_currentIndexChanged(int index)
|
||||
ui->fec->addItem("5/6");
|
||||
ui->fec->addItem("8/9");
|
||||
ui->fec->addItem("9/10");
|
||||
ui->rollOff->addItem("0.20");
|
||||
ui->rollOff->addItem("0.25");
|
||||
ui->rollOff->addItem("0.35");
|
||||
ui->modulation->addItem("QPSK");
|
||||
ui->modulation->addItem("8PSK");
|
||||
ui->modulation->addItem("16APSK");
|
||||
ui->modulation->addItem("32APSK");
|
||||
}
|
||||
else if (m_settings.m_modulation == DATVModSettings::PSK8)
|
||||
{
|
||||
ui->fec->addItem("3/5");
|
||||
ui->fec->addItem("2/3");
|
||||
ui->fec->addItem("3/4");
|
||||
ui->fec->addItem("5/6");
|
||||
ui->fec->addItem("8/9");
|
||||
ui->fec->addItem("9/10");
|
||||
}
|
||||
else if (m_settings.m_modulation == DATVModSettings::APSK16)
|
||||
{
|
||||
ui->fec->addItem("2/3");
|
||||
ui->fec->addItem("3/4");
|
||||
ui->fec->addItem("4/5");
|
||||
ui->fec->addItem("5/6");
|
||||
ui->fec->addItem("8/9");
|
||||
ui->fec->addItem("9/10");
|
||||
}
|
||||
else if (m_settings.m_modulation == DATVModSettings::APSK32)
|
||||
{
|
||||
ui->fec->addItem("3/4");
|
||||
ui->fec->addItem("4/5");
|
||||
ui->fec->addItem("5/6");
|
||||
ui->fec->addItem("8/9");
|
||||
ui->fec->addItem("9/10");
|
||||
}
|
||||
|
||||
ui->fec->setCurrentIndex(ui->fec->findText(DATVModSettings::mapCodeRate(m_settings.m_fec)));
|
||||
ui->rollOff->setCurrentIndex(ui->rollOff->findText(QString("%1").arg(m_settings.m_rollOff, 0, 'f', 2)));
|
||||
ui->modulation->setCurrentIndex(ui->modulation->findText(DATVModSettings::mapModulation(m_settings.m_modulation)));
|
||||
|
||||
ui->fec->blockSignals(false);
|
||||
ui->rollOff->blockSignals(false);
|
||||
ui->modulation->blockSignals(false);
|
||||
|
||||
applySettings();
|
||||
int idx = ui->fec->findText(DATVModSettings::mapCodeRate(m_settings.m_fec));
|
||||
idx = idx == -1 ? 0 : idx;
|
||||
ui->fec->setCurrentIndex(idx);
|
||||
on_fec_currentIndexChanged(idx);
|
||||
}
|
||||
|
||||
void DATVModGUI::on_modulation_currentIndexChanged(int index)
|
||||
{
|
||||
m_settings.m_modulation = (DATVModSettings::DATVModulation) index;
|
||||
if (m_settings.m_standard == DATVModSettings::DVB_S)
|
||||
m_settings.m_modulation = (DATVModSettings::DATVModulation) index;
|
||||
else
|
||||
m_settings.m_modulation = (DATVModSettings::DATVModulation) (index + 1);
|
||||
m_doApplySettings = false;
|
||||
updateFEC();
|
||||
m_doApplySettings = true;
|
||||
applySettings();
|
||||
}
|
||||
|
||||
|
@ -84,6 +84,7 @@ private:
|
||||
void updateWithStreamTime();
|
||||
void setChannelMarkerBandwidth();
|
||||
bool handleMessage(const Message& message);
|
||||
void updateFEC();
|
||||
|
||||
void leaveEvent(QEvent*);
|
||||
void enterEvent(QEvent*);
|
||||
|
@ -246,6 +246,11 @@
|
||||
<string>DVB-S</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>DVB-S2</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -29,8 +29,8 @@
|
||||
const PluginDescriptor DATVModPlugin::m_pluginDescriptor = {
|
||||
DATVMod::m_channelId,
|
||||
QStringLiteral("DATV Modulator"),
|
||||
QStringLiteral("6.6.3"),
|
||||
QStringLiteral("(c) Jon Beniston, M7RCE and Edouard Griffiths, F4EXB"),
|
||||
QStringLiteral("6.7.1"),
|
||||
QStringLiteral("(c) Jon Beniston, M7RCE, Edouard Griffiths, F4EXB. DVB-S2 by G4GUO"),
|
||||
QStringLiteral("https://github.com/f4exb/sdrangel"),
|
||||
true,
|
||||
QStringLiteral("https://github.com/f4exb/sdrangel")
|
||||
|
@ -74,49 +74,10 @@ int DATVModSource::getTSBitrate(const QString& filename)
|
||||
// Get data bitrate (i.e. excluding FEC overhead)
|
||||
int DATVModSource::getDVBSDataBitrate(const DATVModSettings& settings)
|
||||
{
|
||||
float rsFactor = DVBS::tsPacketLen/(float)DVBS::rsPacketLen;
|
||||
float convFactor;
|
||||
float fecFactor;
|
||||
float plFactor;
|
||||
float bitsPerSymbol;
|
||||
|
||||
switch (settings.m_fec)
|
||||
{
|
||||
case DATVModSettings::FEC12:
|
||||
convFactor = 1.0f/2.0f;
|
||||
break;
|
||||
case DATVModSettings::FEC23:
|
||||
convFactor = 2.0f/3.0f;
|
||||
break;
|
||||
case DATVModSettings::FEC34:
|
||||
convFactor = 3.0f/4.0f;
|
||||
break;
|
||||
case DATVModSettings::FEC56:
|
||||
convFactor = 5.0f/6.0f;
|
||||
break;
|
||||
case DATVModSettings::FEC78:
|
||||
convFactor = 7.0f/8.0f;
|
||||
break;
|
||||
case DATVModSettings::FEC45:
|
||||
convFactor = 4.0f/5.0f;
|
||||
break;
|
||||
case DATVModSettings::FEC89:
|
||||
convFactor = 8.0f/9.0f;
|
||||
break;
|
||||
case DATVModSettings::FEC910:
|
||||
convFactor = 9.0f/10.0f;
|
||||
break;
|
||||
case DATVModSettings::FEC14:
|
||||
convFactor = 1.0f/4.0f;
|
||||
break;
|
||||
case DATVModSettings::FEC13:
|
||||
convFactor = 1.0f/3.0f;
|
||||
break;
|
||||
case DATVModSettings::FEC25:
|
||||
convFactor = 2.0f/5.0f;
|
||||
break;
|
||||
case DATVModSettings::FEC35:
|
||||
convFactor = 3.0f/5.0f;
|
||||
break;
|
||||
}
|
||||
switch (settings.m_modulation)
|
||||
{
|
||||
case DATVModSettings::BPSK:
|
||||
@ -136,16 +97,116 @@ int DATVModSource::getDVBSDataBitrate(const DATVModSettings& settings)
|
||||
break;
|
||||
}
|
||||
|
||||
return std::round(settings.m_symbolRate * bitsPerSymbol * rsFactor * convFactor);
|
||||
if (settings.m_standard == DATVModSettings::DVB_S)
|
||||
{
|
||||
float rsFactor;
|
||||
float convFactor;
|
||||
|
||||
rsFactor = DVBS::tsPacketLen/(float)DVBS::rsPacketLen;
|
||||
switch (settings.m_fec)
|
||||
{
|
||||
case DATVModSettings::FEC12:
|
||||
convFactor = 1.0f/2.0f;
|
||||
break;
|
||||
case DATVModSettings::FEC23:
|
||||
convFactor = 2.0f/3.0f;
|
||||
break;
|
||||
case DATVModSettings::FEC34:
|
||||
convFactor = 3.0f/4.0f;
|
||||
break;
|
||||
case DATVModSettings::FEC56:
|
||||
convFactor = 5.0f/6.0f;
|
||||
break;
|
||||
case DATVModSettings::FEC78:
|
||||
convFactor = 7.0f/8.0f;
|
||||
break;
|
||||
case DATVModSettings::FEC45:
|
||||
convFactor = 4.0f/5.0f;
|
||||
break;
|
||||
case DATVModSettings::FEC89:
|
||||
convFactor = 8.0f/9.0f;
|
||||
break;
|
||||
case DATVModSettings::FEC910:
|
||||
convFactor = 9.0f/10.0f;
|
||||
break;
|
||||
case DATVModSettings::FEC14:
|
||||
convFactor = 1.0f/4.0f;
|
||||
break;
|
||||
case DATVModSettings::FEC13:
|
||||
convFactor = 1.0f/3.0f;
|
||||
break;
|
||||
case DATVModSettings::FEC25:
|
||||
convFactor = 2.0f/5.0f;
|
||||
break;
|
||||
case DATVModSettings::FEC35:
|
||||
convFactor = 3.0f/5.0f;
|
||||
break;
|
||||
}
|
||||
fecFactor = rsFactor * convFactor;
|
||||
plFactor = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// For normal frames
|
||||
int codedBlockSize = 64800;
|
||||
int uncodedBlockSize;
|
||||
int bbHeaderBits = 80;
|
||||
// See table 5a in DVBS2 spec
|
||||
switch (settings.m_fec)
|
||||
{
|
||||
case DATVModSettings::FEC12:
|
||||
uncodedBlockSize = 32208;
|
||||
break;
|
||||
case DATVModSettings::FEC23:
|
||||
uncodedBlockSize = 43040;
|
||||
break;
|
||||
case DATVModSettings::FEC34:
|
||||
uncodedBlockSize = 48408;
|
||||
break;
|
||||
case DATVModSettings::FEC56:
|
||||
uncodedBlockSize = 53840;
|
||||
break;
|
||||
case DATVModSettings::FEC45:
|
||||
uncodedBlockSize = 51648;
|
||||
break;
|
||||
case DATVModSettings::FEC89:
|
||||
uncodedBlockSize = 57472;
|
||||
break;
|
||||
case DATVModSettings::FEC910:
|
||||
uncodedBlockSize = 58192;
|
||||
break;
|
||||
case DATVModSettings::FEC14:
|
||||
uncodedBlockSize = 16008;
|
||||
break;
|
||||
case DATVModSettings::FEC13:
|
||||
uncodedBlockSize = 21408;
|
||||
break;
|
||||
case DATVModSettings::FEC25:
|
||||
uncodedBlockSize = 25728;
|
||||
break;
|
||||
case DATVModSettings::FEC35:
|
||||
uncodedBlockSize = 38688;
|
||||
break;
|
||||
default:
|
||||
qDebug() << "DATVModSource::getDVBSDataBitrate: Unsupported DVB-S2 code rate";
|
||||
break;
|
||||
}
|
||||
fecFactor = (uncodedBlockSize-bbHeaderBits)/(float)codedBlockSize;
|
||||
float symbolsPerFrame = codedBlockSize/bitsPerSymbol;
|
||||
// 90 symbols for PL header
|
||||
plFactor = symbolsPerFrame / (symbolsPerFrame + 90.0f);
|
||||
}
|
||||
|
||||
return std::round(settings.m_symbolRate * bitsPerSymbol * fecFactor * plFactor);
|
||||
}
|
||||
|
||||
void DATVModSource::checkBitrates()
|
||||
{
|
||||
int dataBitrate = getDVBSDataBitrate(m_settings);
|
||||
qDebug() << "MPEG-TS bitrate: " << m_mpegTSBitrate;
|
||||
qDebug() << "DVB-S data bitrate: " << dataBitrate;
|
||||
qDebug() << "DVB data bitrate: " << dataBitrate;
|
||||
if (dataBitrate < m_mpegTSBitrate)
|
||||
qWarning() << "DVB-S data bitrate is lower than the bitrate of the MPEG transport stream";
|
||||
qWarning() << "DVB data bitrate is lower than the bitrate of the MPEG transport stream";
|
||||
m_tsRatio = m_mpegTSBitrate/(float)dataBitrate;
|
||||
}
|
||||
|
||||
@ -316,6 +377,12 @@ void DATVModSource::modulateSample()
|
||||
// Encode using DVB-S
|
||||
m_symbolCount = m_dvbs.encode(m_mpegTS, m_iqSymbols);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Encode using DVB-S2
|
||||
m_symbolCount = m_dvbs2.s2_add_ts_frame((u8 *)m_mpegTS);
|
||||
m_plFrame = m_dvbs2.pl_get_frame();
|
||||
}
|
||||
|
||||
// Loop file if we reach the end
|
||||
if ((m_frameIdx*DVBS::tsPacketLen >= m_mpegTSSize) && m_settings.m_tsFilePlayLoop)
|
||||
@ -372,9 +439,17 @@ void DATVModSource::modulateSample()
|
||||
q = m_pulseShapeQ.filter(sin(5*M_PI/4));
|
||||
}
|
||||
*/
|
||||
m_symbolIdx++;
|
||||
m_symbolCount--;
|
||||
}
|
||||
else
|
||||
{
|
||||
// First 90 symbols of DVB-S2 are pi/2 BPSK, then remaining symbols are in specified modulation
|
||||
i = m_pulseShapeI.filter(m_plFrame[m_symbolIdx].re/32767.0);
|
||||
q = m_pulseShapeQ.filter(m_plFrame[m_symbolIdx].im/32767.0);
|
||||
m_symbolIdx++;
|
||||
m_symbolCount--;
|
||||
}
|
||||
m_symbolIdx++;
|
||||
m_symbolCount--;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -621,6 +696,83 @@ void DATVModSource::applySettings(const DATVModSettings& settings, bool force)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dvbs2Format.frame_type = FRAME_NORMAL;
|
||||
m_dvbs2Format.pilots = 0; // PILOTS_OFF;
|
||||
m_dvbs2Format.dummy_frame = 0;
|
||||
m_dvbs2Format.null_deletion = 0;
|
||||
m_dvbs2Format.intface = M_ACM; // Unused?
|
||||
m_dvbs2Format.broadcasting = 1;
|
||||
|
||||
switch (settings.m_modulation)
|
||||
{
|
||||
case DATVModSettings::QPSK:
|
||||
m_dvbs2Format.constellation = M_QPSK;
|
||||
break;
|
||||
case DATVModSettings::PSK8:
|
||||
m_dvbs2Format.constellation = M_8PSK;
|
||||
break;
|
||||
case DATVModSettings::APSK16:
|
||||
m_dvbs2Format.constellation = M_16APSK;
|
||||
break;
|
||||
case DATVModSettings::APSK32:
|
||||
m_dvbs2Format.constellation = M_32APSK;
|
||||
break;
|
||||
default:
|
||||
qDebug() << "DATVModSource::applySettings: Unsupported modulation for DVB-S2";
|
||||
break;
|
||||
}
|
||||
|
||||
switch (settings.m_fec)
|
||||
{
|
||||
case DATVModSettings::FEC12:
|
||||
m_dvbs2Format.code_rate = CR_1_2;
|
||||
break;
|
||||
case DATVModSettings::FEC23:
|
||||
m_dvbs2Format.code_rate = CR_2_3;
|
||||
break;
|
||||
case DATVModSettings::FEC34:
|
||||
m_dvbs2Format.code_rate = CR_3_4;
|
||||
break;
|
||||
case DATVModSettings::FEC56:
|
||||
m_dvbs2Format.code_rate = CR_5_6;
|
||||
break;
|
||||
case DATVModSettings::FEC45:
|
||||
m_dvbs2Format.code_rate = CR_4_5;
|
||||
break;
|
||||
case DATVModSettings::FEC89:
|
||||
m_dvbs2Format.code_rate = CR_8_9;
|
||||
break;
|
||||
case DATVModSettings::FEC910:
|
||||
m_dvbs2Format.code_rate = CR_9_10;
|
||||
break;
|
||||
case DATVModSettings::FEC14:
|
||||
m_dvbs2Format.code_rate = CR_1_4;
|
||||
break;
|
||||
case DATVModSettings::FEC13:
|
||||
m_dvbs2Format.code_rate = CR_1_3;
|
||||
break;
|
||||
case DATVModSettings::FEC25:
|
||||
m_dvbs2Format.code_rate = CR_2_5;
|
||||
break;
|
||||
case DATVModSettings::FEC35:
|
||||
m_dvbs2Format.code_rate = CR_3_5;
|
||||
break;
|
||||
default:
|
||||
qDebug() << "DATVModSource::getDVBSDataBitrate: Unsupported code rate for DVB-S2";
|
||||
break;
|
||||
}
|
||||
|
||||
if (settings.m_rollOff == 0.35f)
|
||||
m_dvbs2Format.roll_off = RO_0_35;
|
||||
else if (settings.m_rollOff == 0.25f)
|
||||
m_dvbs2Format.roll_off = RO_0_25;
|
||||
else
|
||||
m_dvbs2Format.roll_off = RO_0_20;
|
||||
|
||||
m_dvbs2.s2_set_configure(&m_dvbs2Format);
|
||||
}
|
||||
if (getMessageQueueToGUI())
|
||||
{
|
||||
getMessageQueueToGUI()->push(DATVModReport::MsgReportRates::create(
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "datvmodsettings.h"
|
||||
|
||||
#include "dvb-s/dvb-s.h"
|
||||
#include "dvb-s2/DVBS2.h"
|
||||
|
||||
class MessageQueue;
|
||||
class QUdpSocket;
|
||||
@ -88,6 +89,10 @@ private:
|
||||
int m_samplesPerSymbol;
|
||||
uint8_t m_iqSymbols[DVBS::m_maxIQSymbols*2];
|
||||
|
||||
DVBS2 m_dvbs2;
|
||||
DVB2FrameFormat m_dvbs2Format;
|
||||
scmplx *m_plFrame;
|
||||
|
||||
QUdpSocket *m_udpSocket; //!< UDP socket to receive MPEG transport stream via
|
||||
int m_udpByteCount; //!< Count of bytes received via UDP for bitrate calculation
|
||||
boost::chrono::steady_clock::time_point m_udpTimingStart; //!< When we last started counting UDP bytes
|
||||
|
272
plugins/channeltx/moddatv/dvb-s2/DVB2.cpp
Normal file
272
plugins/channeltx/moddatv/dvb-s2/DVB2.cpp
Normal file
@ -0,0 +1,272 @@
|
||||
#include "memory.h"
|
||||
#include "DVB2.h"
|
||||
|
||||
|
||||
//
|
||||
// Update working parameters for the next frame
|
||||
// This prevents parameters changing during a frame
|
||||
//
|
||||
void DVB2::base_end_of_frame_actions(void)
|
||||
{
|
||||
if( m_params_changed )
|
||||
{
|
||||
m_format[0] = m_format[1];
|
||||
ldpc_lookup_generate();
|
||||
m_params_changed = 0;
|
||||
}
|
||||
// reset the pointer
|
||||
m_frame_offset_bits = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// This configures the system and calculates
|
||||
// any required intermediate values
|
||||
//
|
||||
int DVB2::set_configure( DVB2FrameFormat *f )
|
||||
{
|
||||
int bch_bits = 0;
|
||||
int error = 0;
|
||||
|
||||
if( f->broadcasting )
|
||||
{
|
||||
// Set standard parametrs for broadcasting
|
||||
f->frame_type = FRAME_NORMAL;
|
||||
f->bb_header.ts_gs = TS_GS_TRANSPORT;
|
||||
f->bb_header.sis_mis = SIS_MIS_SINGLE;
|
||||
f->bb_header.ccm_acm = CCM;
|
||||
f->bb_header.issyi = 0;
|
||||
f->bb_header.npd = 0;
|
||||
f->bb_header.upl = 188*8;
|
||||
f->bb_header.sync = 0x47;
|
||||
}
|
||||
f->bb_header.ro = f->roll_off;
|
||||
// Fill in the mode specific values and bit lengths
|
||||
if( f->frame_type == FRAME_NORMAL )
|
||||
{
|
||||
f->nldpc = 64800;
|
||||
bch_bits = 192;
|
||||
f->bch_code = BCH_CODE_N12;
|
||||
// Apply code rate
|
||||
switch(f->code_rate )
|
||||
{
|
||||
case CR_1_4:
|
||||
f->q_val = 135;
|
||||
f->kbch = 16008;
|
||||
f->bch_code = BCH_CODE_N12;
|
||||
break;
|
||||
case CR_1_3:
|
||||
f->q_val = 120;
|
||||
f->kbch = 21408;
|
||||
f->bch_code = BCH_CODE_N12;
|
||||
break;
|
||||
case CR_2_5:
|
||||
f->q_val = 108;
|
||||
f->kbch = 25728;
|
||||
f->bch_code = BCH_CODE_N12;
|
||||
break;
|
||||
case CR_1_2:
|
||||
f->q_val = 90;
|
||||
f->kbch = 32208;
|
||||
f->bch_code = BCH_CODE_N12;
|
||||
break;
|
||||
case CR_3_5:
|
||||
f->q_val = 72;
|
||||
f->kbch = 38688;
|
||||
f->bch_code = BCH_CODE_N12;
|
||||
break;
|
||||
case CR_2_3:
|
||||
bch_bits = 160;
|
||||
f->q_val = 60;
|
||||
f->kbch = 43040;
|
||||
f->bch_code = BCH_CODE_N10;
|
||||
break;
|
||||
case CR_3_4:
|
||||
f->q_val = 45;
|
||||
f->kbch = 48408;
|
||||
f->bch_code = BCH_CODE_N12;
|
||||
break;
|
||||
case CR_4_5:
|
||||
f->q_val = 36;
|
||||
f->kbch = 51648;
|
||||
f->bch_code = BCH_CODE_N12;
|
||||
break;
|
||||
case CR_5_6:
|
||||
bch_bits = 160;
|
||||
f->q_val = 30;
|
||||
f->kbch = 53840;
|
||||
f->bch_code = BCH_CODE_N10;
|
||||
break;
|
||||
case CR_8_9:
|
||||
bch_bits = 128;
|
||||
f->q_val = 20;
|
||||
f->kbch = 57472;
|
||||
f->bch_code = BCH_CODE_N8;
|
||||
break;
|
||||
case CR_9_10:
|
||||
bch_bits = 128;
|
||||
f->q_val = 18;
|
||||
f->kbch = 58192;
|
||||
f->bch_code = BCH_CODE_N8;
|
||||
break;
|
||||
default:
|
||||
// loggerf("Configuration error DVB2\n");
|
||||
error = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( f->frame_type == FRAME_SHORT )
|
||||
{
|
||||
f->nldpc = 16200;
|
||||
bch_bits = 168;
|
||||
f->bch_code = BCH_CODE_S12;
|
||||
// Apply code rate
|
||||
switch(f->code_rate )
|
||||
{
|
||||
case CR_1_4:
|
||||
f->q_val = 36;
|
||||
f->kbch = 3072;
|
||||
break;
|
||||
case CR_1_3:
|
||||
f->q_val = 30;
|
||||
f->kbch = 5232;
|
||||
break;
|
||||
case CR_2_5:
|
||||
f->q_val = 27;
|
||||
f->kbch = 6312;
|
||||
break;
|
||||
case CR_1_2:
|
||||
f->q_val = 25;
|
||||
f->kbch = 7032;
|
||||
break;
|
||||
case CR_3_5:
|
||||
f->q_val = 18;
|
||||
f->kbch = 9552;
|
||||
break;
|
||||
case CR_2_3:
|
||||
f->q_val = 15;
|
||||
f->kbch = 10632;
|
||||
break;
|
||||
case CR_3_4:
|
||||
f->q_val = 12;
|
||||
f->kbch = 11712;
|
||||
break;
|
||||
case CR_4_5:
|
||||
f->q_val = 10;
|
||||
f->kbch = 12432;
|
||||
break;
|
||||
case CR_5_6:
|
||||
f->q_val = 8;
|
||||
f->kbch = 13152;
|
||||
break;
|
||||
case CR_8_9:
|
||||
f->q_val = 5;
|
||||
f->kbch = 14232;
|
||||
break;
|
||||
case CR_9_10:
|
||||
error = 1;
|
||||
f->kbch = 0;
|
||||
break;
|
||||
default:
|
||||
// loggerf("Configuration error DVB2\n");
|
||||
error = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( error == 0 )
|
||||
{
|
||||
// Length of the user packets
|
||||
f->bb_header.upl = 188*8;
|
||||
// Payload length
|
||||
f->bb_header.dfl = f->kbch - 80;
|
||||
// Transport packet sync
|
||||
f->bb_header.sync = 0x47;
|
||||
// Start of LDPC bits
|
||||
f->kldpc = f->kbch + bch_bits;
|
||||
// Number of padding bits required (not used)
|
||||
f->padding_bits = 0;
|
||||
// Number of useable data bits (not used)
|
||||
f->useable_data_bits = f->kbch - 80;
|
||||
// Save the configuration, will be updated on next frame
|
||||
m_format[1] = *f;
|
||||
// reset various pointers
|
||||
m_dnp = 0;// No deleted null packets
|
||||
// Signal we need to update on the next frame.
|
||||
if( m_params_changed )
|
||||
base_end_of_frame_actions();
|
||||
else
|
||||
m_params_changed = 1;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
void DVB2::get_configure( DVB2FrameFormat *f )
|
||||
{
|
||||
*f = m_format[1];
|
||||
}
|
||||
|
||||
// Points to first byte in transport packet
|
||||
|
||||
int DVB2::add_ts_frame_base( u8 *ts )
|
||||
{
|
||||
if( m_frame_offset_bits == 0 )
|
||||
{
|
||||
// New frame needs to be sent
|
||||
add_bbheader(); // Add the header
|
||||
}
|
||||
// Add a new transport packet
|
||||
unpack_transport_packet_add_crc( ts );
|
||||
// Have we reached the end?
|
||||
if( m_frame_offset_bits == m_format[0].kbch )
|
||||
{
|
||||
// Yes so now Scramble the BB frame
|
||||
bb_randomise();
|
||||
// BCH encode the BB Frame
|
||||
bch_encode();
|
||||
// LDPC encode the BB frame and BCHFEC bits
|
||||
ldpc_encode();
|
||||
// Signal to the modulation specific class we have something to send
|
||||
base_end_of_frame_actions();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
//
|
||||
// Dump NULL packets appends a counter to the end of each UP
|
||||
// it is not implemented at the moment.
|
||||
//
|
||||
int DVB2::next_ts_frame_base( u8 *ts )
|
||||
{
|
||||
int res = 0;
|
||||
// See if we need to dump null packets
|
||||
if( m_format[0].null_deletion == 1 )
|
||||
{
|
||||
if(((ts[0]&0x1F) == 0x1F)&&(ts[1] == 0xFF ))
|
||||
{
|
||||
// Null packet detected
|
||||
if( m_dnp < 0xFF )
|
||||
{
|
||||
m_dnp++;// Increment the number of null packets
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Need to send a new transport packet
|
||||
res = add_ts_frame_base( ts );
|
||||
if( res ) m_dnp = 0;// Clear the DNP counter
|
||||
// return whether it is time to transmit a new frame
|
||||
return res;
|
||||
}
|
||||
DVB2::DVB2(void)
|
||||
{
|
||||
// Clear the transport queue
|
||||
m_tp_q.empty();
|
||||
init_bb_randomiser();
|
||||
bch_poly_build_tables();
|
||||
build_crc8_table();
|
||||
m_dnp = 0;// No delted null packets
|
||||
m_frame_offset_bits = 0;
|
||||
m_params_changed = 1;
|
||||
}
|
||||
DVB2::~DVB2(void)
|
||||
{
|
||||
}
|
218
plugins/channeltx/moddatv/dvb-s2/DVB2.h
Normal file
218
plugins/channeltx/moddatv/dvb-s2/DVB2.h
Normal file
@ -0,0 +1,218 @@
|
||||
#ifndef DVB2_H
|
||||
#define DVB2_H
|
||||
#include <queue>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned char u8;
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
// BB HEADER fileds
|
||||
#define TS_GS_TRANSPORT 3
|
||||
#define TS_GS_GENERIC_PACKETIZED 0
|
||||
#define TS_GS_GENERIC_CONTINUOUS 1
|
||||
#define TS_GS_RESERVED 2
|
||||
|
||||
#define SIS_MIS_SINGLE 1
|
||||
#define SIS_MIS_MULTIPLE 0
|
||||
|
||||
#define CCM 1
|
||||
#define ACM 0
|
||||
|
||||
#define ISSYI_ACTIVE 1
|
||||
#define ISSYI_NOT_ACTIVE 0
|
||||
|
||||
#define NPD_ACTIVE 1
|
||||
#define NPD_NOT_ACTIVE 0
|
||||
// Rolloff
|
||||
#define RO_0_35 0
|
||||
#define RO_0_25 1
|
||||
#define RO_0_20 2
|
||||
#define RO_RESERVED 3
|
||||
|
||||
// Pilots
|
||||
#define PILOTS_OFF 0
|
||||
#define PILOTS_ON 1
|
||||
|
||||
typedef struct{
|
||||
int ts_gs;
|
||||
int sis_mis;
|
||||
int ccm_acm;
|
||||
int issyi;
|
||||
int npd;
|
||||
int ro;
|
||||
int isi;
|
||||
int upl;
|
||||
int dfl;
|
||||
int sync;
|
||||
int syncd;
|
||||
}BBHeader;
|
||||
|
||||
typedef int Bit;
|
||||
|
||||
// The number of useable and stuff bits in a frame
|
||||
typedef struct{
|
||||
int data_bits;
|
||||
int stuff_bits;
|
||||
}FrameBits;
|
||||
|
||||
#define FRAME_SIZE_NORMAL 64800
|
||||
#define FRAME_SIZE_SHORT 16200
|
||||
#define LDPC_ENCODE_TABLE_LENGTH (FRAME_SIZE_NORMAL*10)
|
||||
|
||||
typedef struct{
|
||||
int table_length;
|
||||
Bit d[LDPC_ENCODE_TABLE_LENGTH];
|
||||
Bit p[LDPC_ENCODE_TABLE_LENGTH];
|
||||
}Ldpc_encode_table;
|
||||
|
||||
#define FRAME_NORMAL 0x00
|
||||
#define FRAME_SHORT 0x10
|
||||
#define BB_HEADER_LENGTH_BITS 72
|
||||
#define CRC8_LENGTH_BITS 8
|
||||
|
||||
#define PADDING_LENGTH 200
|
||||
|
||||
// Code rates
|
||||
#define CR_1_4 0
|
||||
#define CR_1_3 1
|
||||
#define CR_2_5 2
|
||||
#define CR_1_2 3
|
||||
#define CR_3_5 4
|
||||
#define CR_2_3 5
|
||||
#define CR_3_4 6
|
||||
#define CR_4_5 7
|
||||
#define CR_5_6 8
|
||||
#define CR_8_9 9
|
||||
#define CR_9_10 10
|
||||
// BCH Code
|
||||
#define BCH_CODE_N8 0
|
||||
#define BCH_CODE_N10 1
|
||||
#define BCH_CODE_N12 2
|
||||
#define BCH_CODE_S12 3
|
||||
// Constellation
|
||||
#define M_QPSK 0
|
||||
#define M_8PSK 1
|
||||
#define M_16APSK 2
|
||||
#define M_32APSK 3
|
||||
//Interface
|
||||
#define M_ACM 0
|
||||
#define M_CCM 1
|
||||
#define M_VCM 2
|
||||
|
||||
|
||||
typedef struct{
|
||||
int frame_type;
|
||||
int code_rate;
|
||||
int roll_off;
|
||||
int constellation;
|
||||
int pilots;
|
||||
int dummy_frame;
|
||||
int null_deletion;
|
||||
int intface;
|
||||
int broadcasting;
|
||||
// Calculated information, not used by caller
|
||||
BBHeader bb_header;
|
||||
int kldpc;
|
||||
int kbch;
|
||||
int nldpc;
|
||||
int q_val;
|
||||
int bch_code;
|
||||
int useable_data_bits;
|
||||
int padding_bits;
|
||||
int total_bits;
|
||||
int nr_tps;
|
||||
int nr_tps_bits;
|
||||
}DVB2FrameFormat;
|
||||
|
||||
|
||||
class DVB2{
|
||||
|
||||
public:
|
||||
|
||||
protected:
|
||||
Bit m_frame[FRAME_SIZE_NORMAL];
|
||||
DVB2FrameFormat m_format[2];
|
||||
Bit m_padding[PADDING_LENGTH];
|
||||
int m_frame_offset_bits;
|
||||
int m_params_changed;
|
||||
|
||||
private:
|
||||
int m_bbheader[BB_HEADER_LENGTH_BITS+CRC8_LENGTH_BITS];
|
||||
int m_bb_randomise[FRAME_SIZE_NORMAL];
|
||||
u32 m_poly_n_8[4];
|
||||
u32 m_poly_n_10[5];
|
||||
u32 m_poly_n_12[6];
|
||||
u32 m_poly_s_12[6];
|
||||
u8 m_crc_tab[256];
|
||||
u8 m_dnp; // Deleted null packet
|
||||
// Transport packet queue
|
||||
queue <u8> m_tp_q;
|
||||
|
||||
// LDPC tables
|
||||
const static int ldpc_tab_1_4N[45][13];
|
||||
const static int ldpc_tab_1_3N[60][13];
|
||||
const static int ldpc_tab_2_5N[72][13];
|
||||
const static int ldpc_tab_1_2N[90][9];
|
||||
const static int ldpc_tab_3_5N[108][13];
|
||||
const static int ldpc_tab_2_3N[120][14];
|
||||
const static int ldpc_tab_3_4N[135][13];
|
||||
const static int ldpc_tab_4_5N[144][12];
|
||||
const static int ldpc_tab_5_6N[150][14];
|
||||
const static int ldpc_tab_8_9N[160][5];
|
||||
const static int ldpc_tab_9_10N[162][5];
|
||||
const static int ldpc_tab_1_4S[9][13];
|
||||
const static int ldpc_tab_1_3S[15][13];
|
||||
const static int ldpc_tab_2_5S[18][13];
|
||||
const static int ldpc_tab_1_2S[20][9];
|
||||
const static int ldpc_tab_3_5S[27][13];
|
||||
const static int ldpc_tab_2_3S[30][14];
|
||||
const static int ldpc_tab_3_4S[33][13];
|
||||
const static int ldpc_tab_4_5S[35][4];
|
||||
const static int ldpc_tab_5_6S[37][14];
|
||||
const static int ldpc_tab_8_9S[40][5];
|
||||
|
||||
|
||||
Ldpc_encode_table m_ldpc_encode;
|
||||
void bb_randomise(void);
|
||||
void init_scrambler(void);
|
||||
void init_bb_randomiser(void);
|
||||
void ldpc_lookup_generate(void);
|
||||
void ldpc_encode( void );
|
||||
int add_transport_packet( u8 *pkt, Bit *b );
|
||||
void build_crc8_table( void );
|
||||
u8 calc_crc8( u8 *b, int len );
|
||||
int add_crc8_bits( Bit *in, int length );
|
||||
void unpack_transport_packet_add_crc( u8 *ts );
|
||||
void add_bbheader( void );
|
||||
void poly_reverse( int *pin, int *pout, int len );
|
||||
void poly_pack( const int *pin, u32* pout, int len );
|
||||
int poly_mult( const int *ina, int lena, const int *inb, int lenb, int *out );
|
||||
void bch_poly_build_tables( void );
|
||||
void reg_4_shift( u32 *sr );
|
||||
void reg_5_shift( u32 *sr );
|
||||
void reg_6_shift( u32 *sr );
|
||||
Bit bch_n_8_encode( Bit *in, int len );
|
||||
Bit bch_n_10_encode( Bit *in, int len );
|
||||
Bit bch_n_12_encode( Bit *in, int len );
|
||||
Bit bch_s_12_encode( Bit *in, int len );
|
||||
int bch_encode( void );
|
||||
int add_ts_frame_base( u8 *ts );
|
||||
void ldpc_encode_test();
|
||||
void base_end_of_frame_actions(void);
|
||||
protected:
|
||||
int set_configure( DVB2FrameFormat *f );
|
||||
void get_configure( DVB2FrameFormat *f );
|
||||
int next_ts_frame_base( u8 *ts );
|
||||
public:
|
||||
// encode a new transport packet
|
||||
// virtual void physical(void);
|
||||
DVB2();
|
||||
~DVB2();
|
||||
};
|
||||
|
||||
#endif
|
156
plugins/channeltx/moddatv/dvb-s2/DVBS2.cpp
Normal file
156
plugins/channeltx/moddatv/dvb-s2/DVBS2.cpp
Normal file
@ -0,0 +1,156 @@
|
||||
#include "memory.h"
|
||||
#include "DVBS2.h"
|
||||
|
||||
//
|
||||
// called at the end of a frame
|
||||
//
|
||||
void DVBS2::end_of_frame_actions(void)
|
||||
{
|
||||
if( m_s2_config_updated )
|
||||
{
|
||||
modulator_configuration();
|
||||
m_s2_config_updated = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int DVBS2::is_valid( int mod, int coderate )
|
||||
{
|
||||
if( mod == M_QPSK )
|
||||
{
|
||||
if(coderate == CR_1_4) return 0;
|
||||
if(coderate == CR_1_3) return 0;
|
||||
if(coderate == CR_2_5) return 0;
|
||||
if(coderate == CR_1_2) return 0;
|
||||
if(coderate == CR_3_5) return 0;
|
||||
if(coderate == CR_2_3) return 0;
|
||||
if(coderate == CR_3_4) return 0;
|
||||
if(coderate == CR_4_5) return 0;
|
||||
if(coderate == CR_5_6) return 0;
|
||||
if(coderate == CR_8_9) return 0;
|
||||
if(coderate == CR_9_10) return 0;
|
||||
}
|
||||
if( mod == M_8PSK )
|
||||
{
|
||||
if(coderate == CR_3_5) return 0;
|
||||
if(coderate == CR_2_3) return 0;
|
||||
if(coderate == CR_3_4) return 0;
|
||||
if(coderate == CR_5_6) return 0;
|
||||
if(coderate == CR_8_9) return 0;
|
||||
if(coderate == CR_9_10) return 0;
|
||||
}
|
||||
if( mod == M_16APSK )
|
||||
{
|
||||
if(coderate == CR_2_3) return 0;
|
||||
if(coderate == CR_3_4) return 0;
|
||||
if(coderate == CR_4_5) return 0;
|
||||
if(coderate == CR_5_6) return 0;
|
||||
if(coderate == CR_8_9) return 0;
|
||||
if(coderate == CR_9_10) return 0;
|
||||
}
|
||||
if( mod == M_32APSK )
|
||||
{
|
||||
if(coderate == CR_3_4) return 0;
|
||||
if(coderate == CR_4_5) return 0;
|
||||
if(coderate == CR_5_6) return 0;
|
||||
if(coderate == CR_8_9) return 0;
|
||||
if(coderate == CR_9_10) return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
//
|
||||
// index 0 and 1 will only be different when being reconfigured.
|
||||
// Use index 1 as this will be applied in the following transmit
|
||||
// frames
|
||||
//
|
||||
void DVBS2::calc_efficiency( void )
|
||||
{
|
||||
double p,m,a,s,b,po;
|
||||
// Calculate the number of symbols in the payload
|
||||
p = 0;a = 0; m = 0;
|
||||
if( m_format[1].frame_type == FRAME_NORMAL ) p = (double)FRAME_SIZE_NORMAL;
|
||||
if( m_format[1].frame_type == FRAME_SHORT ) p = (double)FRAME_SIZE_SHORT;
|
||||
if( m_format[1].constellation == M_QPSK ) m = 2.0;
|
||||
if( m_format[1].constellation == M_8PSK ) m = 3.0;
|
||||
if( m_format[1].constellation == M_16APSK ) m = 4.0;
|
||||
if( m_format[1].constellation == M_32APSK ) m = 5.0;
|
||||
s = p/m;//Number of symbols per frame
|
||||
// PL header overhead
|
||||
if( m_format[1].pilots )
|
||||
{
|
||||
po = (s/(90*16))-1;// 1 pilot every 16 blocks (of 90 symbols)
|
||||
po = po*36; // No pilot at the end
|
||||
a = s/(90+po+s);
|
||||
}
|
||||
else
|
||||
{
|
||||
a = s/(90+s);// No pilots
|
||||
}
|
||||
// Modulation efficiency
|
||||
a = a*m;
|
||||
// Take into account pilot symbols
|
||||
// TBD
|
||||
// Now calculate the useable data as percentage of the frame
|
||||
b = ((double)m_format[1].useable_data_bits)/p;
|
||||
// Now calculate the efficiency by multiplying the
|
||||
// useable bits efficiency by the modulation efficiency
|
||||
m_efficiency = b*a;
|
||||
}
|
||||
//
|
||||
// Multiply the efficiency value by the symbol rate
|
||||
// to get the useable bitrate
|
||||
//
|
||||
double DVBS2::s2_get_efficiency( void )
|
||||
{
|
||||
return m_efficiency;
|
||||
}
|
||||
|
||||
int DVBS2::s2_set_configure( DVB2FrameFormat *f )
|
||||
{
|
||||
if( is_valid( f->constellation, f->code_rate ) == 0 )
|
||||
{
|
||||
if( set_configure( f ) == 0 )
|
||||
{
|
||||
calc_efficiency();
|
||||
m_s2_config_updated = 1;
|
||||
m_configured = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
void DVBS2::s2_get_configure( DVB2FrameFormat *f )
|
||||
{
|
||||
get_configure( f );
|
||||
}
|
||||
int DVBS2::s2_add_ts_frame( u8 *ts )
|
||||
{
|
||||
int res = 0;
|
||||
if (m_configured == 0) return 0;
|
||||
// Call base class
|
||||
if( next_ts_frame_base( ts ) )
|
||||
{
|
||||
// Interleave and pack
|
||||
s2_interleave();
|
||||
// create the header
|
||||
s2_pl_header_create();
|
||||
// Add the data
|
||||
res = s2_pl_data_pack();
|
||||
// Do any updates required for the next frame
|
||||
end_of_frame_actions();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
void DVBS2::physical( void )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
DVBS2::DVBS2()
|
||||
{
|
||||
m_configured = 0;
|
||||
modulator_configuration();
|
||||
build_symbol_scrambler_table();
|
||||
pl_build_dummy();
|
||||
}
|
||||
|
65
plugins/channeltx/moddatv/dvb-s2/DVBS2.h
Normal file
65
plugins/channeltx/moddatv/dvb-s2/DVBS2.h
Normal file
@ -0,0 +1,65 @@
|
||||
#include "DVB2.h"
|
||||
|
||||
#ifndef __SCMPLX__
|
||||
typedef struct{
|
||||
short re;
|
||||
short im;
|
||||
}scmplx;
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef DVBS2_H
|
||||
#define DVBS2_H
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159f
|
||||
#endif
|
||||
|
||||
#define loggerf printf
|
||||
|
||||
class DVBS2 : public DVB2{
|
||||
private:
|
||||
const static unsigned long g[6];
|
||||
const static int ph_scram_tab[64];
|
||||
const static int ph_sync_seq[26];
|
||||
scmplx m_bpsk[2][2];
|
||||
scmplx m_qpsk[4];
|
||||
scmplx m_8psk[8];
|
||||
scmplx m_16apsk[16];
|
||||
scmplx m_32apsk[32];
|
||||
scmplx m_pl[FRAME_SIZE_NORMAL];
|
||||
scmplx m_pl_dummy[FRAME_SIZE_NORMAL];
|
||||
int m_cscram[FRAME_SIZE_NORMAL];
|
||||
int m_iframe[FRAME_SIZE_NORMAL];
|
||||
int m_payload_symbols;
|
||||
int m_dummy_frame_length;
|
||||
int m_configured;
|
||||
double m_efficiency;
|
||||
int m_s2_config_updated;
|
||||
void b_64_7_code( unsigned char in, int *out );
|
||||
void s2_pl_header_encode( u8 modcod, u8 type, int *out);
|
||||
void modulator_configuration(void);
|
||||
void s2_interleave( void );
|
||||
void s2_pl_header_create(void);
|
||||
int s2_pl_data_pack( void );
|
||||
void pl_scramble_symbols( scmplx *fs, int len );
|
||||
void pl_scramble_dummy_symbols( int len );
|
||||
void pl_build_dummy( void );
|
||||
int parity_chk( long a, long b);
|
||||
void build_symbol_scrambler_table( void );
|
||||
void calc_efficiency( void );
|
||||
void end_of_frame_actions(void);
|
||||
|
||||
public:
|
||||
int is_valid(int mod, int coderate);
|
||||
double s2_get_efficiency( void );
|
||||
void physical(void);
|
||||
int s2_set_configure( DVB2FrameFormat *f );
|
||||
void s2_get_configure( DVB2FrameFormat *f );
|
||||
scmplx *pl_get_frame(void);
|
||||
scmplx *pl_get_dummy( int &len );
|
||||
int s2_add_ts_frame( u8 *ts );
|
||||
DVBS2();
|
||||
};
|
||||
|
||||
#endif
|
149
plugins/channeltx/moddatv/dvb-s2/dvb2_bbheader.cpp
Normal file
149
plugins/channeltx/moddatv/dvb-s2/dvb2_bbheader.cpp
Normal file
@ -0,0 +1,149 @@
|
||||
#include "DVB2.h"
|
||||
#include "memory.h"
|
||||
//
|
||||
// This file adds the BB header and new transport packets
|
||||
//
|
||||
#define CRC_POLY 0xAB
|
||||
// Reversed
|
||||
#define CRC_POLYR 0xD5
|
||||
|
||||
void DVB2::build_crc8_table( void )
|
||||
{
|
||||
int r,crc;
|
||||
|
||||
for( int i = 0; i < 256; i++ )
|
||||
{
|
||||
r = i;
|
||||
crc = 0;
|
||||
for( int j = 7; j >= 0; j-- )
|
||||
{
|
||||
if((r&(1<<j)?1:0) ^ ((crc&0x80)?1:0))
|
||||
crc = (crc<<1)^CRC_POLYR;
|
||||
else
|
||||
crc <<= 1;
|
||||
}
|
||||
m_crc_tab[i] = crc;
|
||||
}
|
||||
}
|
||||
|
||||
u8 DVB2::calc_crc8( u8 *b, int len )
|
||||
{
|
||||
u8 crc = 0;
|
||||
|
||||
for( int i = 0; i < len; i++ )
|
||||
{
|
||||
crc = m_crc_tab[b[i]^crc];
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
//
|
||||
// MSB is sent first
|
||||
//
|
||||
// The polynomial has been reversed, this is only used for the BB header
|
||||
//
|
||||
|
||||
int DVB2::add_crc8_bits( Bit *in, int length )
|
||||
{
|
||||
int crc = 0;
|
||||
int b;
|
||||
int i = 0;
|
||||
|
||||
for( int n = 0; n < length; n++ )
|
||||
{
|
||||
b = in[i++] ^ (crc&0x01);
|
||||
crc >>= 1;
|
||||
if( b ) crc ^= CRC_POLY;
|
||||
}
|
||||
|
||||
for( int n = 0; n < 8; n++ )
|
||||
{
|
||||
in[i++] = (crc&(1<<n))? 1 : 0;
|
||||
}
|
||||
return 8;// Length of CRC
|
||||
}
|
||||
|
||||
//
|
||||
// Formatted into a binary array
|
||||
//
|
||||
void DVB2::add_bbheader( void )
|
||||
{
|
||||
int temp;
|
||||
BBHeader *h = &m_format[0].bb_header;
|
||||
|
||||
m_frame[0] = h->ts_gs>>1;
|
||||
m_frame[1] = h->ts_gs&1;
|
||||
m_frame[2] = h->sis_mis;
|
||||
m_frame[3] = h->ccm_acm;
|
||||
m_frame[4] = h->issyi&1;
|
||||
m_frame[5] = h->npd&1;
|
||||
m_frame[6] = h->ro>>1;
|
||||
m_frame[7] = h->ro&1;
|
||||
m_frame_offset_bits = 8;
|
||||
if( h->sis_mis == SIS_MIS_MULTIPLE )
|
||||
{
|
||||
temp = h->isi;
|
||||
for( int n = 7; n >= 0; n-- )
|
||||
{
|
||||
m_frame[m_frame_offset_bits++] = temp&(1<<n)? 1 : 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( int n = 7; n >= 0 ; n-- )
|
||||
{
|
||||
m_frame[m_frame_offset_bits++] = 0;
|
||||
}
|
||||
}
|
||||
temp = h->upl;
|
||||
for( int n = 15; n >= 0; n-- )
|
||||
{
|
||||
m_frame[m_frame_offset_bits++] = temp&(1<<n)?1:0;
|
||||
}
|
||||
temp = h->dfl;
|
||||
for( int n = 15; n >= 0; n-- )
|
||||
{
|
||||
m_frame[m_frame_offset_bits++] = temp&(1<<n)?1:0;
|
||||
}
|
||||
temp = h->sync;
|
||||
for( int n = 7; n >= 0; n-- )
|
||||
{
|
||||
m_frame[m_frame_offset_bits++] = temp&(1<<n)?1:0;
|
||||
}
|
||||
// Calculate syncd, this should point to the MSB of the CRC
|
||||
temp = m_tp_q.size();
|
||||
if( temp == 0 )
|
||||
temp = 187*8;
|
||||
else
|
||||
temp = (temp-1)*8;
|
||||
//temp = h->syncd;// Syncd
|
||||
for( int n = 15; n >= 0; n-- )
|
||||
{
|
||||
m_frame[m_frame_offset_bits++] = temp&(1<<n)?1:0;
|
||||
}
|
||||
// Add CRC to BB header, at end
|
||||
int len = BB_HEADER_LENGTH_BITS;
|
||||
m_frame_offset_bits += add_crc8_bits( m_frame, len );
|
||||
}
|
||||
|
||||
void DVB2::unpack_transport_packet_add_crc( u8 *ts )
|
||||
{
|
||||
// CRC is added in place of sync byte at end of packet
|
||||
// skip the header 0x47
|
||||
u8 crc = calc_crc8( &ts[1], 188-1 );
|
||||
// Add the transport packet to the transport queue
|
||||
for( int i = 1; i < 188; i++ ) m_tp_q.push( ts[i] );
|
||||
// Add the crc
|
||||
m_tp_q.push(crc);
|
||||
// now pull off the transport queue and fill the frame
|
||||
while((m_tp_q.size()!= 0)&&(m_frame_offset_bits!=m_format[0].kbch))
|
||||
{
|
||||
// Add to the frame bit array
|
||||
u8 b = m_tp_q.front();
|
||||
m_tp_q.pop();
|
||||
for( int n = 7; n >= 0; n-- )
|
||||
{
|
||||
m_frame[m_frame_offset_bits++] = b&(1<<n)? 1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
408
plugins/channeltx/moddatv/dvb-s2/dvb2_bch.cpp
Normal file
408
plugins/channeltx/moddatv/dvb-s2/dvb2_bch.cpp
Normal file
@ -0,0 +1,408 @@
|
||||
// polymult.cpp : Defines the entry point for the console application.
|
||||
//
|
||||
#include "stdio.h"
|
||||
#include "stdlib.h"
|
||||
#include "memory.h"
|
||||
#include "DVBS2.h"
|
||||
|
||||
|
||||
//
|
||||
// Display routines.
|
||||
//
|
||||
void display_poly( int *in, int len )
|
||||
{
|
||||
loggerf("\n");
|
||||
for( int i = 0; i < len; i++ )
|
||||
{
|
||||
if(in[i] == 1 )
|
||||
{
|
||||
if( i == 0 )
|
||||
loggerf("1");
|
||||
else
|
||||
if( i == 1 )
|
||||
loggerf("+x");
|
||||
else
|
||||
loggerf("+x^%d",i);
|
||||
}
|
||||
}
|
||||
loggerf("\n");
|
||||
}
|
||||
//
|
||||
// length is in bits
|
||||
//
|
||||
void display_poly_pack( unsigned int *in, int len )
|
||||
{
|
||||
(void) in;
|
||||
// loggerf("\n");
|
||||
for( int i = 0; i < len/32; i++ )
|
||||
{
|
||||
// loggerf("%.8X",in[i]);
|
||||
}
|
||||
switch((len%32)/8)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
// loggerf("%.2X",in[(len/32)]>>24);
|
||||
break;
|
||||
case 2:
|
||||
// loggerf("%.2X",in[(len/32)]>>24);
|
||||
// loggerf("%.2X",in[(len/32)]>>16);
|
||||
break;
|
||||
case 3:
|
||||
// loggerf("%.2X",in[(len/32)]>>24);
|
||||
// loggerf("%.2X",in[(len/32)]>>16);
|
||||
// loggerf("%.2X",in[(len/32)]>>8);
|
||||
break;
|
||||
}
|
||||
// loggerf("\n");
|
||||
}
|
||||
|
||||
//
|
||||
// Polynomial calculation routines
|
||||
//
|
||||
// multiply polynomials
|
||||
//
|
||||
int DVB2::poly_mult( const int *ina, int lena, const int *inb, int lenb, int *out )
|
||||
{
|
||||
memset( out, 0, sizeof(int)*(lena+lenb));
|
||||
|
||||
for( int i = 0; i < lena; i++ )
|
||||
{
|
||||
for( int j = 0; j < lenb; j++ )
|
||||
{
|
||||
if( ina[i]*inb[j] > 0 ) out[i+j]++;// count number of terms for this pwr of x
|
||||
}
|
||||
}
|
||||
int max=0;
|
||||
for( int i = 0; i < lena+lenb; i++ )
|
||||
{
|
||||
out[i] = out[i]&1;// If even ignore the term
|
||||
if(out[i]) max = i;
|
||||
}
|
||||
// return the size of array to house the result.
|
||||
return max+1;
|
||||
|
||||
}
|
||||
//
|
||||
// Pack the polynomial into a 32 bit array
|
||||
//
|
||||
|
||||
void DVB2::poly_pack( const int *pin, u32* pout, int len )
|
||||
{
|
||||
int lw = len/32;
|
||||
int ptr = 0;
|
||||
u32 temp;
|
||||
if( len % 32 ) lw++;
|
||||
|
||||
for( int i = 0; i < lw; i++ )
|
||||
{
|
||||
temp = 0x80000000;
|
||||
pout[i] = 0;
|
||||
for( int j = 0; j < 32; j++ )
|
||||
{
|
||||
if( pin[ptr++] ) pout[i] |= temp;
|
||||
temp >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DVB2::poly_reverse( int *pin, int *pout, int len )
|
||||
{
|
||||
int c;
|
||||
c = len-1;
|
||||
|
||||
for( int i = 0; i < len; i++ )
|
||||
{
|
||||
pout[c--] = pin[i];
|
||||
}
|
||||
}
|
||||
//
|
||||
// Shift a 128 bit register
|
||||
//
|
||||
void inline DVB2::reg_4_shift( u32 *sr )
|
||||
{
|
||||
sr[3] = (sr[3]>>1) | (sr[2]<<31);
|
||||
sr[2] = (sr[2]>>1) | (sr[1]<<31);
|
||||
sr[1] = (sr[1]>>1) | (sr[0]<<31);
|
||||
sr[0] = (sr[0]>>1);
|
||||
}
|
||||
//
|
||||
// Shift 160 bits
|
||||
//
|
||||
void inline DVB2::reg_5_shift( u32 *sr )
|
||||
{
|
||||
sr[4] = (sr[4]>>1) | (sr[3]<<31);
|
||||
sr[3] = (sr[3]>>1) | (sr[2]<<31);
|
||||
sr[2] = (sr[2]>>1) | (sr[1]<<31);
|
||||
sr[1] = (sr[1]>>1) | (sr[0]<<31);
|
||||
sr[0] = (sr[0]>>1);
|
||||
}
|
||||
//
|
||||
// Shift 192 bits
|
||||
//
|
||||
void inline DVB2::reg_6_shift( u32 *sr )
|
||||
{
|
||||
sr[5] = (sr[5]>>1) | (sr[4]<<31);
|
||||
sr[4] = (sr[4]>>1) | (sr[3]<<31);
|
||||
sr[3] = (sr[3]>>1) | (sr[2]<<31);
|
||||
sr[2] = (sr[2]>>1) | (sr[1]<<31);
|
||||
sr[1] = (sr[1]>>1) | (sr[0]<<31);
|
||||
sr[0] = (sr[0]>>1);
|
||||
}
|
||||
|
||||
//
|
||||
// Take an bit array, bch encode it and place the result in a bit array
|
||||
// The input length is in bits.
|
||||
//
|
||||
Bit DVB2::bch_n_8_encode( Bit *in, int len )
|
||||
{
|
||||
Bit b;
|
||||
int i;
|
||||
u32 shift[4];
|
||||
|
||||
//Zero the shift register
|
||||
memset( shift,0,sizeof(u32)*4);
|
||||
|
||||
for( i = 0; i < len; i++ )
|
||||
{
|
||||
b = in[i]^(shift[3]&1);
|
||||
reg_4_shift( shift );
|
||||
if( b )
|
||||
{
|
||||
shift[0] ^= m_poly_n_8[0];
|
||||
shift[1] ^= m_poly_n_8[1];
|
||||
shift[2] ^= m_poly_n_8[2];
|
||||
shift[3] ^= m_poly_n_8[3];
|
||||
}
|
||||
}
|
||||
// Now add the parity bits to the output
|
||||
for( int n = 0; n < 128; n++ )
|
||||
{
|
||||
in[i++] = shift[3]&1;
|
||||
reg_4_shift( shift );
|
||||
}
|
||||
return i;
|
||||
}
|
||||
Bit DVB2::bch_n_10_encode( Bit *in,int len )
|
||||
{
|
||||
Bit b;
|
||||
int i;
|
||||
u32 shift[5];
|
||||
|
||||
//Zero the shift register
|
||||
memset( shift,0,sizeof(u32)*5);
|
||||
|
||||
for( i = 0; i < len; i++ )
|
||||
{
|
||||
b = in[i]^(shift[4]&1);
|
||||
reg_5_shift( shift );
|
||||
if(b)
|
||||
{
|
||||
shift[0] ^= m_poly_n_10[0];
|
||||
shift[1] ^= m_poly_n_10[1];
|
||||
shift[2] ^= m_poly_n_10[2];
|
||||
shift[3] ^= m_poly_n_10[3];
|
||||
shift[4] ^= m_poly_n_10[4];
|
||||
}
|
||||
}
|
||||
// Now add the parity bits to the output
|
||||
for( int n = 0; n < 160; n++ )
|
||||
{
|
||||
in[i++] = shift[4]&1;
|
||||
reg_5_shift( shift );
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
Bit DVB2::bch_n_12_encode( Bit *in, int len )
|
||||
{
|
||||
Bit b;
|
||||
int i;
|
||||
u32 shift[6];
|
||||
//Zero the shift register
|
||||
memset( shift,0,sizeof(u32)*6);
|
||||
// MSB of the codeword first
|
||||
for( i = 0; i < len; i++ )
|
||||
{
|
||||
b = in[i] ^ (shift[5]&1);
|
||||
reg_6_shift( shift );
|
||||
if(b)
|
||||
{
|
||||
shift[0] ^= m_poly_n_12[0];
|
||||
shift[1] ^= m_poly_n_12[1];
|
||||
shift[2] ^= m_poly_n_12[2];
|
||||
shift[3] ^= m_poly_n_12[3];
|
||||
shift[4] ^= m_poly_n_12[4];
|
||||
shift[5] ^= m_poly_n_12[5];
|
||||
}
|
||||
}
|
||||
// Now add the parity bits to the output
|
||||
for( int n = 0; n < 192; n++ )
|
||||
{
|
||||
in[i++] = shift[5]&1;
|
||||
reg_6_shift( shift );
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
Bit DVB2::bch_s_12_encode( Bit *in, int len )
|
||||
{
|
||||
Bit b;
|
||||
int i;
|
||||
u32 shift[6];
|
||||
|
||||
//Zero the shift register
|
||||
memset( shift,0,sizeof(u32)*6);
|
||||
|
||||
for( i = 0; i < len; i++ )
|
||||
{
|
||||
b = (in[i] ^ ((shift[5]&0x01000000)?1:0));
|
||||
reg_6_shift( shift );
|
||||
if(b)
|
||||
{
|
||||
shift[0] ^= m_poly_s_12[0];
|
||||
shift[1] ^= m_poly_s_12[1];
|
||||
shift[2] ^= m_poly_s_12[2];
|
||||
shift[3] ^= m_poly_s_12[3];
|
||||
shift[4] ^= m_poly_s_12[4];
|
||||
shift[5] ^= m_poly_s_12[5];
|
||||
}
|
||||
}
|
||||
// Now add the parity bits to the output
|
||||
for( int n = 0; n < 168; n++ )
|
||||
{
|
||||
in[i++] = (shift[5]&0x01000000) ? 1:0;
|
||||
reg_6_shift( shift );
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
int DVB2::bch_encode( void )
|
||||
{
|
||||
int res;
|
||||
int len = m_format[0].kbch;
|
||||
|
||||
switch(m_format[0].bch_code)
|
||||
{
|
||||
case BCH_CODE_N8:
|
||||
res = bch_n_8_encode( m_frame, len );
|
||||
break;
|
||||
case BCH_CODE_N10:
|
||||
res = bch_n_10_encode( m_frame, len );
|
||||
break;
|
||||
case BCH_CODE_N12:
|
||||
res = bch_n_12_encode( m_frame, len );
|
||||
break;
|
||||
case BCH_CODE_S12:
|
||||
res = bch_s_12_encode( m_frame, len );
|
||||
break;
|
||||
default:
|
||||
printf("BCH error situation\n");
|
||||
res = 0;
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
void DVB2::bch_poly_build_tables( void )
|
||||
{
|
||||
// Normal polynomials
|
||||
const int polyn01[]={1,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,1};
|
||||
const int polyn02[]={1,1,0,0,1,1,1,0,1,0,0,0,0,0,0,0,1};
|
||||
const int polyn03[]={1,0,1,1,1,1,0,1,1,1,1,1,0,0,0,0,1};
|
||||
const int polyn04[]={1,0,1,0,1,0,1,0,0,1,0,1,1,0,1,0,1};
|
||||
const int polyn05[]={1,1,1,1,0,1,0,0,1,1,1,1,1,0,0,0,1};
|
||||
const int polyn06[]={1,0,1,0,1,1,0,1,1,1,1,0,1,1,1,1,1};
|
||||
const int polyn07[]={1,0,1,0,0,1,1,0,1,1,1,1,0,1,0,1,1};
|
||||
const int polyn08[]={1,1,1,0,0,1,1,0,1,1,0,0,1,1,1,0,1};
|
||||
const int polyn09[]={1,0,0,0,0,1,0,1,0,1,1,1,0,0,0,0,1};
|
||||
const int polyn10[]={1,1,1,0,0,1,0,1,1,0,1,0,1,1,1,0,1};
|
||||
const int polyn11[]={1,0,1,1,0,1,0,0,0,1,0,1,1,1,0,0,1};
|
||||
const int polyn12[]={1,1,0,0,0,1,1,1,0,1,0,1,1,0,0,0,1};
|
||||
|
||||
// Short polynomials
|
||||
const int polys01[]={1,1,0,1,0,1,0,0,0,0,0,0,0,0,1};
|
||||
const int polys02[]={1,0,0,0,0,0,1,0,1,0,0,1,0,0,1};
|
||||
const int polys03[]={1,1,1,0,0,0,1,0,0,1,1,0,0,0,1};
|
||||
const int polys04[]={1,0,0,0,1,0,0,1,1,0,1,0,1,0,1};
|
||||
const int polys05[]={1,0,1,0,1,0,1,0,1,1,0,1,0,1,1};
|
||||
const int polys06[]={1,0,0,1,0,0,0,1,1,1,0,0,0,1,1};
|
||||
const int polys07[]={1,0,1,0,0,1,1,1,0,0,1,1,0,1,1};
|
||||
const int polys08[]={1,0,0,0,0,1,0,0,1,1,1,1,0,0,1};
|
||||
const int polys09[]={1,1,1,1,0,0,0,0,0,1,1,0,0,0,1};
|
||||
const int polys10[]={1,0,0,1,0,0,1,0,0,1,0,1,1,0,1};
|
||||
const int polys11[]={1,0,0,0,1,0,0,0,0,0,0,1,1,0,1};
|
||||
const int polys12[]={1,1,1,1,0,1,1,1,1,0,1,0,0,1,1};
|
||||
|
||||
int len;
|
||||
int polyout[3][2000];
|
||||
|
||||
len = poly_mult( polyn01, 17, polyn02, 17, polyout[0] );
|
||||
len = poly_mult( polyn03, 17, polyout[0], len, polyout[1] );
|
||||
len = poly_mult( polyn04, 17, polyout[1], len, polyout[0] );
|
||||
len = poly_mult( polyn05, 17, polyout[0], len, polyout[1] );
|
||||
len = poly_mult( polyn06, 17, polyout[1], len, polyout[0] );
|
||||
len = poly_mult( polyn07, 17, polyout[0], len, polyout[1] );
|
||||
len = poly_mult( polyn08, 17, polyout[1], len, polyout[0] );
|
||||
poly_pack( polyout[0], m_poly_n_8, 128 );
|
||||
// display_poly_pack( m_poly_n_8, 128);
|
||||
|
||||
len = poly_mult( polyn09, 17, polyout[0], len, polyout[1] );
|
||||
len = poly_mult( polyn10, 17, polyout[1], len, polyout[0] );
|
||||
poly_pack( polyout[0], m_poly_n_10, 160 );
|
||||
// display_poly_pack( m_poly_n_10, 160);
|
||||
|
||||
len = poly_mult( polyn11, 17, polyout[0], len, polyout[1] );
|
||||
len = poly_mult( polyn12, 17, polyout[1], len, polyout[0] );
|
||||
poly_pack( polyout[0], m_poly_n_12, 192 );
|
||||
// display_poly_pack( m_poly_n_12, 192);
|
||||
// display_poly( polyout[0], len );//12
|
||||
|
||||
|
||||
len = poly_mult( polys01, 15, polys02, 15, polyout[0] );
|
||||
len = poly_mult( polys03, 15, polyout[0], len, polyout[1] );
|
||||
len = poly_mult( polys04, 15, polyout[1], len, polyout[0] );
|
||||
len = poly_mult( polys05, 15, polyout[0], len, polyout[1] );
|
||||
len = poly_mult( polys06, 15, polyout[1], len, polyout[0] );
|
||||
len = poly_mult( polys07, 15, polyout[0], len, polyout[1] );
|
||||
len = poly_mult( polys08, 15, polyout[1], len, polyout[0] );
|
||||
len = poly_mult( polys09, 15, polyout[0], len, polyout[1] );
|
||||
len = poly_mult( polys10, 15, polyout[1], len, polyout[0] );
|
||||
len = poly_mult( polys11, 15, polyout[0], len, polyout[1] );
|
||||
len = poly_mult( polys12, 15, polyout[1], len, polyout[0] );
|
||||
poly_pack( polyout[0], m_poly_s_12, 168 );
|
||||
// display_poly_pack( m_poly_s_12, 168);
|
||||
|
||||
/*
|
||||
// test
|
||||
int pt1[] = {1,1};
|
||||
int pt2[] = {1,1,1};
|
||||
int pt3[] = {1,0,1,1,1,1};
|
||||
len = poly_mult( pt1, 2, pt2, 3, polyout[0] );
|
||||
len = poly_mult( pt3, 6, polyout[0], len, polyout[1] );
|
||||
display_poly( polyout[1], len );
|
||||
poly_pack( polyout[1], m_poly_s_12, len );
|
||||
display_poly_pack( m_poly_s_12, 8 );
|
||||
u32 shift[6];
|
||||
shift[0] = 0x80000000;
|
||||
shift[1] = 0x00000000;
|
||||
shift[2] = 0x00000000;
|
||||
shift[3] = 0x00000000;
|
||||
shift[4] = 0x00000000;
|
||||
shift[5] = 0x00000000;
|
||||
|
||||
for( int i = 0; i < 192; i++ )
|
||||
{
|
||||
display_poly_pack( shift, 192 );
|
||||
reg_6_shift( shift );
|
||||
}
|
||||
|
||||
// display_poly( polyout[0], len );//12
|
||||
// display_poly_pack( m_poly_s_12, 168 );// Wont work because of shift register length
|
||||
*/
|
||||
}
|
157
plugins/channeltx/moddatv/dvb-s2/dvb2_ldpc_encode.cpp
Normal file
157
plugins/channeltx/moddatv/dvb-s2/dvb2_ldpc_encode.cpp
Normal file
@ -0,0 +1,157 @@
|
||||
#include "memory.h"
|
||||
#include "DVB2.h"
|
||||
|
||||
/*
|
||||
for( int row = 0; row < rows; row++ )
|
||||
{
|
||||
for( int n = 0; n < 360; n++ )
|
||||
{
|
||||
for( int col = 1; col <= table_name[row][0]; col++ )
|
||||
{
|
||||
// parity bit location, position from start of block
|
||||
m_ldpc_encode.p[index] = m_format.kldpc + (table_name[row][col] + (n*m_format.q_val))%pbits;
|
||||
// data bit to be accumulated
|
||||
m_ldpc_encode.d[index] = im;
|
||||
index++;
|
||||
}
|
||||
im++;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
#define LDPC_BF( TABLE_NAME, ROWS ) \
|
||||
for( int row = 0; row < ROWS; row++ ) \
|
||||
{ \
|
||||
for( int n = 0; n < 360; n++ ) \
|
||||
{ \
|
||||
for( int col = 1; col <= TABLE_NAME[row][0]; col++ ) \
|
||||
{ \
|
||||
m_ldpc_encode.p[index] = (TABLE_NAME[row][col] + (n*q))%pbits; \
|
||||
m_ldpc_encode.d[index] = im; \
|
||||
index++; \
|
||||
} \
|
||||
im++; \
|
||||
} \
|
||||
}
|
||||
|
||||
/*
|
||||
//
|
||||
// Generate the lookup tables for the ldpc mode
|
||||
//
|
||||
void DVBS2::ldpc_lookup_generate( void )
|
||||
{
|
||||
int im;
|
||||
int index;
|
||||
int pbits;
|
||||
int uc;
|
||||
int rows;
|
||||
|
||||
index = 0;
|
||||
im = 0;
|
||||
|
||||
if(m_format.frame_type == FRAME_NORMAL)
|
||||
{
|
||||
if(m_format.code_rate == CR_2_3)
|
||||
{
|
||||
uc = m_format.kldpc;
|
||||
pbits = m_format.nldpc - m_format.kldpc; //number of parity bits
|
||||
rows = 120;
|
||||
|
||||
for( int row = 0; row < rows; row++ )// for each row
|
||||
{
|
||||
for( int n = 0; n < 360; n++ )
|
||||
{
|
||||
for( int col = 1; col <= ldpc_tab_2_3N[row][0]; col++ )
|
||||
{
|
||||
// parity bit location, position from start of block
|
||||
m_ldpc_encode.p[index] = m_format.kldpc + (ldpc_tab_2_3N[row][col] + (n*m_format.q_val))%pbits;
|
||||
// data bit to be accumulated
|
||||
m_ldpc_encode.d[index] = im;
|
||||
index++;
|
||||
}
|
||||
im++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m_ldpc_encode.length = index;
|
||||
}
|
||||
*/
|
||||
void DVB2::ldpc_lookup_generate( void )
|
||||
{
|
||||
int im;
|
||||
int index;
|
||||
int pbits;
|
||||
int q;
|
||||
index = 0;
|
||||
im = 0;
|
||||
|
||||
pbits = m_format[0].nldpc - m_format[0].kldpc; //number of parity bits
|
||||
q = m_format[0].q_val;
|
||||
|
||||
if(m_format[0].frame_type == FRAME_NORMAL)
|
||||
{
|
||||
if( m_format[0].code_rate == CR_1_4 ) LDPC_BF( ldpc_tab_1_4N, 45 );
|
||||
if( m_format[0].code_rate == CR_1_3 ) LDPC_BF( ldpc_tab_1_3N, 60 );
|
||||
if( m_format[0].code_rate == CR_2_5 ) LDPC_BF( ldpc_tab_2_5N, 72 );
|
||||
if( m_format[0].code_rate == CR_1_2 ) LDPC_BF( ldpc_tab_1_2N, 90 );
|
||||
if( m_format[0].code_rate == CR_3_5 ) LDPC_BF( ldpc_tab_3_5N, 108 );
|
||||
if( m_format[0].code_rate == CR_2_3 ) LDPC_BF( ldpc_tab_2_3N, 120 );
|
||||
if( m_format[0].code_rate == CR_3_4 ) LDPC_BF( ldpc_tab_3_4N, 135 );
|
||||
if( m_format[0].code_rate == CR_4_5 ) LDPC_BF( ldpc_tab_4_5N, 144 );
|
||||
if( m_format[0].code_rate == CR_5_6 ) LDPC_BF( ldpc_tab_5_6N, 150 );
|
||||
if( m_format[0].code_rate == CR_8_9 ) LDPC_BF( ldpc_tab_8_9N, 160 );
|
||||
if( m_format[0].code_rate == CR_9_10) LDPC_BF( ldpc_tab_9_10N, 162 );
|
||||
}
|
||||
if(m_format[0].frame_type == FRAME_SHORT)
|
||||
{
|
||||
if( m_format[0].code_rate == CR_1_4 ) LDPC_BF( ldpc_tab_1_4S, 9 );
|
||||
if( m_format[0].code_rate == CR_1_3 ) LDPC_BF( ldpc_tab_1_3S, 15 );
|
||||
if( m_format[0].code_rate == CR_2_5 ) LDPC_BF( ldpc_tab_2_5S, 18 );
|
||||
if( m_format[0].code_rate == CR_1_2 ) LDPC_BF( ldpc_tab_1_2S, 20 );
|
||||
if( m_format[0].code_rate == CR_3_5 ) LDPC_BF( ldpc_tab_3_5S, 27 );
|
||||
if( m_format[0].code_rate == CR_2_3 ) LDPC_BF( ldpc_tab_2_3S, 30 );
|
||||
if( m_format[0].code_rate == CR_3_4 ) LDPC_BF( ldpc_tab_3_4S, 33 );
|
||||
if( m_format[0].code_rate == CR_4_5 ) LDPC_BF( ldpc_tab_4_5S, 35 );
|
||||
if( m_format[0].code_rate == CR_5_6 ) LDPC_BF( ldpc_tab_5_6S, 37 );
|
||||
if( m_format[0].code_rate == CR_8_9 ) LDPC_BF( ldpc_tab_8_9S, 40 );
|
||||
}
|
||||
m_ldpc_encode.table_length = index;
|
||||
}
|
||||
|
||||
void DVB2::ldpc_encode( void )
|
||||
{
|
||||
Bit *d,*p;
|
||||
// Calculate the number of parity bits
|
||||
int plen = m_format[0].nldpc - m_format[0].kldpc;
|
||||
d = m_frame;
|
||||
p = &m_frame[m_format[0].kldpc];
|
||||
// First zero all the parity bits
|
||||
memset( p, 0, sizeof(Bit)*plen);
|
||||
|
||||
// now do the parity checking
|
||||
for( int i = 0; i < m_ldpc_encode.table_length; i++ )
|
||||
{
|
||||
p[m_ldpc_encode.p[i]] ^= d[m_ldpc_encode.d[i]];
|
||||
}
|
||||
for (int i = 1; i < plen; i++)
|
||||
{
|
||||
p[i] ^= p[i - 1];
|
||||
}
|
||||
}
|
||||
void DVB2::ldpc_encode_test( void )
|
||||
{
|
||||
if(1)// m_format.code_rate == CR_1_2 )
|
||||
{
|
||||
printf("\n\nEncode length %d\n",m_ldpc_encode.table_length);
|
||||
printf("Parity start %d\n",m_format[0].kldpc);
|
||||
for( int i = 0; i < m_ldpc_encode.table_length; i++ )
|
||||
{
|
||||
if(m_ldpc_encode.d[i] == 0 )
|
||||
{
|
||||
printf("%d+%d\n",m_ldpc_encode.p[i],m_ldpc_encode.d[i]);
|
||||
}
|
||||
}
|
||||
printf("Encode test end\n\n");
|
||||
}
|
||||
}
|
1595
plugins/channeltx/moddatv/dvb-s2/dvb2_ldpc_tables.cpp
Normal file
1595
plugins/channeltx/moddatv/dvb-s2/dvb2_ldpc_tables.cpp
Normal file
File diff suppressed because it is too large
Load Diff
23
plugins/channeltx/moddatv/dvb-s2/dvb2_scrambler.cpp
Normal file
23
plugins/channeltx/moddatv/dvb-s2/dvb2_scrambler.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
#include "DVB2.h"
|
||||
|
||||
void DVB2::init_bb_randomiser(void)
|
||||
{
|
||||
int sr = 0x4A80;
|
||||
for( int i = 0; i < FRAME_SIZE_NORMAL; i++ )
|
||||
{
|
||||
int b = ((sr)^(sr>>1))&1;
|
||||
m_bb_randomise[i] = b;
|
||||
sr >>= 1;
|
||||
if( b ) sr |= 0x4000;
|
||||
}
|
||||
}
|
||||
//
|
||||
// Randomise the data bits
|
||||
//
|
||||
void DVB2::bb_randomise(void)
|
||||
{
|
||||
for( int i = 0; i < m_format[0].kbch; i++ )
|
||||
{
|
||||
m_frame[i] ^= m_bb_randomise[i];
|
||||
}
|
||||
}
|
89
plugins/channeltx/moddatv/dvb-s2/dvbs2_interleave.cpp
Normal file
89
plugins/channeltx/moddatv/dvb-s2/dvbs2_interleave.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
#include "memory.h"
|
||||
#include "DVBS2.h"
|
||||
//
|
||||
// The output is bit packed ready for modulating
|
||||
//
|
||||
void DVBS2::s2_interleave( void )
|
||||
{
|
||||
int index=0;
|
||||
int rows=0;
|
||||
|
||||
int frame_size = m_format[0].nldpc;
|
||||
|
||||
if( m_format[0].constellation == M_QPSK )
|
||||
{
|
||||
rows = frame_size/2;
|
||||
m_payload_symbols = rows;
|
||||
for( int i = 0; i < rows; i++ )
|
||||
{
|
||||
m_iframe[i] = (m_frame[index++]<<1);
|
||||
m_iframe[i] |= m_frame[index++];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if( m_format[0].constellation == M_8PSK )
|
||||
{
|
||||
if( m_format[0].code_rate == CR_3_5 )
|
||||
{
|
||||
rows = frame_size/3;
|
||||
m_payload_symbols = rows;
|
||||
Bit *c1,*c2,*c3;
|
||||
c1 = &m_frame[rows*2];
|
||||
c2 = &m_frame[rows];
|
||||
c3 = &m_frame[0];
|
||||
for( int i = 0; i < rows; i++ )
|
||||
{
|
||||
m_iframe[i] = (c1[i]<<2) | (c2[i]<<1) | (c3[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rows = frame_size/3;
|
||||
m_payload_symbols = rows;
|
||||
Bit *c1,*c2,*c3;
|
||||
c1 = &m_frame[0];
|
||||
c2 = &m_frame[rows];
|
||||
c3 = &m_frame[rows*2];
|
||||
for( int i = 0; i < rows; i++ )
|
||||
{
|
||||
m_iframe[i] = (c1[i]<<2) | (c2[i]<<1) | (c3[i]);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if( m_format[0].constellation == M_16APSK )
|
||||
{
|
||||
rows = frame_size/4;
|
||||
m_payload_symbols = rows;
|
||||
Bit *c1,*c2,*c3,*c4;
|
||||
c1 = &m_frame[0];
|
||||
c2 = &m_frame[rows];
|
||||
c3 = &m_frame[rows*2];
|
||||
c4 = &m_frame[rows*3];
|
||||
for( int i = 0; i < rows; i++ )
|
||||
{
|
||||
m_iframe[i] = (c1[i]<<3) | (c2[i]<<2) | (c3[i]<<1) | (c4[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if( m_format[0].constellation == M_32APSK )
|
||||
{
|
||||
rows = frame_size/5;
|
||||
m_payload_symbols = rows;
|
||||
Bit *c1,*c2,*c3,*c4,*c5;
|
||||
c1 = &m_frame[0];
|
||||
c2 = &m_frame[rows];
|
||||
c3 = &m_frame[rows*2];
|
||||
c4 = &m_frame[rows*3];
|
||||
c5 = &m_frame[rows*4];
|
||||
for( int i = 0; i < rows; i++ )
|
||||
{
|
||||
m_iframe[i] = (c1[i]<<4) | (c2[i]<<3) | (c3[i]<<2) | (c4[i]<<1) | c5[i];
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
209
plugins/channeltx/moddatv/dvb-s2/dvbs2_modulator.cpp
Normal file
209
plugins/channeltx/moddatv/dvb-s2/dvbs2_modulator.cpp
Normal file
@ -0,0 +1,209 @@
|
||||
#include "math.h"
|
||||
#include "DVBS2.h"
|
||||
|
||||
#define CP 0x7FFF
|
||||
|
||||
void DVBS2::modulator_configuration()
|
||||
{
|
||||
double r0,r1,r2,r3;
|
||||
double m = 1.0;
|
||||
if (m_format[0].constellation == M_32APSK)
|
||||
r0 = 0.9*m;// I am not sure why this needs to be 0.9 but 32APSK does not work if == 1.0
|
||||
else
|
||||
r0 = 1.0*m;// Don't use 0.9 for other mods, as that results in worse MER
|
||||
r1 = m;
|
||||
// BPSK
|
||||
m_bpsk[0][0].re = (short)((r0*cos(1*M_PI/4.0))*CP);
|
||||
m_bpsk[0][0].im = (short)((r0*sin(1*M_PI/4.0))*CP);
|
||||
m_bpsk[0][1].re = (short)((r0*cos(5*M_PI/4.0))*CP);
|
||||
m_bpsk[0][1].im = (short)((r0*sin(5*M_PI/4.0))*CP);
|
||||
|
||||
m_bpsk[1][0].re = (short)((r0*cos(3*M_PI/4.0))*CP);
|
||||
m_bpsk[1][0].im = (short)((r0*sin(3*M_PI/4.0))*CP);
|
||||
m_bpsk[1][1].re = (short)((r0*cos(7*M_PI/4.0))*CP);
|
||||
m_bpsk[1][1].im = (short)((r0*sin(7*M_PI/4.0))*CP);
|
||||
|
||||
// QPSK
|
||||
m_qpsk[0].re = (short)((r1*cos(M_PI/4.0))*CP);
|
||||
m_qpsk[0].im = (short)((r1*sin(M_PI/4.0))*CP);
|
||||
m_qpsk[1].re = (short)((r1*cos(7*M_PI/4.0))*CP);
|
||||
m_qpsk[1].im = (short)((r1*sin(7*M_PI/4.0))*CP);
|
||||
m_qpsk[2].re = (short)((r1*cos(3*M_PI/4.0))*CP);
|
||||
m_qpsk[2].im = (short)((r1*sin(3*M_PI/4.0))*CP);
|
||||
m_qpsk[3].re = (short)((r1*cos(5*M_PI/4.0))*CP);
|
||||
m_qpsk[3].im = (short)((r1*sin(5*M_PI/4.0))*CP);
|
||||
|
||||
// 8PSK
|
||||
m_8psk[0].re = (short)((r1*cos(M_PI/4.0))*CP);
|
||||
m_8psk[0].im = (short)((r1*sin(M_PI/4.0))*CP);
|
||||
m_8psk[1].re = (short)((r1*cos(0.0))*CP);
|
||||
m_8psk[1].im = (short)((r1*sin(0.0))*CP);
|
||||
m_8psk[2].re = (short)((r1*cos(4*M_PI/4.0))*CP);
|
||||
m_8psk[2].im = (short)((r1*sin(4*M_PI/4.0))*CP);
|
||||
m_8psk[3].re = (short)((r1*cos(5*M_PI/4.0))*CP);
|
||||
m_8psk[3].im = (short)((r1*sin(5*M_PI/4.0))*CP);
|
||||
m_8psk[4].re = (short)((r1*cos(2*M_PI/4.0))*CP);
|
||||
m_8psk[4].im = (short)((r1*sin(2*M_PI/4.0))*CP);
|
||||
m_8psk[5].re = (short)((r1*cos(7*M_PI/4.0))*CP);
|
||||
m_8psk[5].im = (short)((r1*sin(7*M_PI/4.0))*CP);
|
||||
m_8psk[6].re = (short)((r1*cos(3*M_PI/4.0))*CP);
|
||||
m_8psk[6].im = (short)((r1*sin(3*M_PI/4.0))*CP);
|
||||
m_8psk[7].re = (short)((r1*cos(6*M_PI/4.0))*CP);
|
||||
m_8psk[7].im = (short)((r1*sin(6*M_PI/4.0))*CP);
|
||||
|
||||
// 16 APSK
|
||||
r2 = m;
|
||||
switch( m_format[0].code_rate )
|
||||
{
|
||||
case CR_2_3:
|
||||
r1 = r2/3.15;
|
||||
break;
|
||||
case CR_3_4:
|
||||
r1 = r2/2.85;
|
||||
break;
|
||||
case CR_4_5:
|
||||
r1 = r2/2.75;
|
||||
break;
|
||||
case CR_5_6:
|
||||
r1 = r2/2.70;
|
||||
break;
|
||||
case CR_8_9:
|
||||
r1 = r2/2.60;
|
||||
break;
|
||||
case CR_9_10:
|
||||
r1 = r2/2.57;
|
||||
break;
|
||||
default:
|
||||
// Illegal
|
||||
r1 = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
m_16apsk[0].re = (short)((r2*cos(M_PI/4.0))*CP);
|
||||
m_16apsk[0].im = (short)((r2*sin(M_PI/4.0))*CP);
|
||||
m_16apsk[1].re = (short)((r2*cos(-M_PI/4.0))*CP);
|
||||
m_16apsk[1].im = (short)((r2*sin(-M_PI/4.0))*CP);
|
||||
m_16apsk[2].re = (short)((r2*cos(3*M_PI/4.0))*CP);
|
||||
m_16apsk[2].im = (short)((r2*sin(3*M_PI/4.0))*CP);
|
||||
m_16apsk[3].re = (short)((r2*cos(-3*M_PI/4.0))*CP);
|
||||
m_16apsk[3].im = (short)((r2*sin(-3*M_PI/4.0))*CP);
|
||||
m_16apsk[4].re = (short)((r2*cos(M_PI/12.0))*CP);
|
||||
m_16apsk[4].im = (short)((r2*sin(M_PI/12.0))*CP);
|
||||
m_16apsk[5].re = (short)((r2*cos(-M_PI/12.0))*CP);
|
||||
m_16apsk[5].im = (short)((r2*sin(-M_PI/12.0))*CP);
|
||||
m_16apsk[6].re = (short)((r2*cos(11*M_PI/12.0))*CP);
|
||||
m_16apsk[6].im = (short)((r2*sin(11*M_PI/12.0))*CP);
|
||||
m_16apsk[7].re = (short)((r2*cos(-11*M_PI/12.0))*CP);
|
||||
m_16apsk[7].im = (short)((r2*sin(-11*M_PI/12.0))*CP);
|
||||
m_16apsk[8].re = (short)((r2*cos(5*M_PI/12.0))*CP);
|
||||
m_16apsk[8].im = (short)((r2*sin(5*M_PI/12.0))*CP);
|
||||
m_16apsk[9].re = (short)((r2*cos(-5*M_PI/12.0))*CP);
|
||||
m_16apsk[9].im = (short)((r2*sin(-5*M_PI/12.0))*CP);
|
||||
m_16apsk[10].re = (short)((r2*cos(7*M_PI/12.0))*CP);
|
||||
m_16apsk[10].im = (short)((r2*sin(7*M_PI/12.0))*CP);
|
||||
m_16apsk[11].re = (short)((r2*cos(-7*M_PI/12.0))*CP);
|
||||
m_16apsk[11].im = (short)((r2*sin(-7*M_PI/12.0))*CP);
|
||||
m_16apsk[12].re = (short)((r1*cos(M_PI/4.0))*CP);
|
||||
m_16apsk[12].im = (short)((r1*sin(M_PI/4.0))*CP);
|
||||
m_16apsk[13].re = (short)((r1*cos(-M_PI/4.0))*CP);
|
||||
m_16apsk[13].im = (short)((r1*sin(-M_PI/4.0))*CP);
|
||||
m_16apsk[14].re = (short)((r1*cos(3*M_PI/4.0))*CP);
|
||||
m_16apsk[14].im = (short)((r1*sin(3*M_PI/4.0))*CP);
|
||||
m_16apsk[15].re = (short)((r1*cos(-3*M_PI/4.0))*CP);
|
||||
m_16apsk[15].im = (short)((r1*sin(-3*M_PI/4.0))*CP);
|
||||
// 32 APSK
|
||||
r3 = m;
|
||||
switch( m_format[0].code_rate )
|
||||
{
|
||||
case CR_3_4:
|
||||
r1 = r3/5.27;
|
||||
r2 = r1*2.84;
|
||||
break;
|
||||
case CR_4_5:
|
||||
r1 = r3/4.87;
|
||||
r2 = r1*2.72;
|
||||
break;
|
||||
case CR_5_6:
|
||||
r1 = r3/4.64;
|
||||
r2 = r1*2.64;
|
||||
break;
|
||||
case CR_8_9:
|
||||
r1 = r3/4.33;
|
||||
r2 = r1*2.54;
|
||||
break;
|
||||
case CR_9_10:
|
||||
r1 = r3/4.30;
|
||||
r2 = r1*2.53;
|
||||
break;
|
||||
default:
|
||||
// Illegal
|
||||
r1 = 0;
|
||||
r2 = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
m_32apsk[0].re = (short)((r2*cos(M_PI/4.0))*CP);
|
||||
m_32apsk[0].im = (short)((r2*sin(M_PI/4.0))*CP);
|
||||
m_32apsk[1].re = (short)((r2*cos(5*M_PI/12.0))*CP);
|
||||
m_32apsk[1].im = (short)((r2*sin(5*M_PI/12.0))*CP);
|
||||
m_32apsk[2].re = (short)((r2*cos(-M_PI/4.0))*CP);
|
||||
m_32apsk[2].im = (short)((r2*sin(-M_PI/4.0))*CP);
|
||||
m_32apsk[3].re = (short)((r2*cos(-5*M_PI/12.0))*CP);
|
||||
m_32apsk[3].im = (short)((r2*sin(-5*M_PI/12.0))*CP);
|
||||
m_32apsk[4].re = (short)((r2*cos(3*M_PI/4.0))*CP);
|
||||
m_32apsk[4].im = (short)((r2*sin(3*M_PI/4.0))*CP);
|
||||
m_32apsk[5].re = (short)((r2*cos(7*M_PI/12.0))*CP);
|
||||
m_32apsk[5].im = (short)((r2*sin(7*M_PI/12.0))*CP);
|
||||
m_32apsk[6].re = (short)((r2*cos(-3*M_PI/4.0))*CP);
|
||||
m_32apsk[6].im = (short)((r2*sin(-3*M_PI/4.0))*CP);
|
||||
m_32apsk[7].re = (short)((r2*cos(-7*M_PI/12.0))*CP);
|
||||
m_32apsk[7].im = (short)((r2*sin(-7*M_PI/12.0))*CP);
|
||||
m_32apsk[8].re = (short)((r3*cos(M_PI/8.0))*CP);
|
||||
m_32apsk[8].im = (short)((r3*sin(M_PI/8.0))*CP);
|
||||
m_32apsk[9].re = (short)((r3*cos(3*M_PI/8.0))*CP);
|
||||
m_32apsk[9].im = (short)((r3*sin(3*M_PI/8.0))*CP);
|
||||
m_32apsk[10].re = (short)((r3*cos(-M_PI/4.0))*CP);
|
||||
m_32apsk[10].im = (short)((r3*sin(-M_PI/4.0))*CP);
|
||||
m_32apsk[11].re = (short)((r3*cos(-M_PI/2.0))*CP);
|
||||
m_32apsk[11].im = (short)((r3*sin(-M_PI/2.0))*CP);
|
||||
m_32apsk[12].re = (short)((r3*cos(3*M_PI/4.0))*CP);
|
||||
m_32apsk[12].im = (short)((r3*sin(3*M_PI/4.0))*CP);
|
||||
m_32apsk[13].re = (short)((r3*cos(M_PI/2.0))*CP);
|
||||
m_32apsk[13].im = (short)((r3*sin(M_PI/2.0))*CP);
|
||||
m_32apsk[14].re = (short)((r3*cos(-7*M_PI/8.0))*CP);
|
||||
m_32apsk[14].im = (short)((r3*sin(-7*M_PI/8.0))*CP);
|
||||
m_32apsk[15].re = (short)((r3*cos(-5*M_PI/8.0))*CP);
|
||||
m_32apsk[15].im = (short)((r3*sin(-5*M_PI/8.0))*CP);
|
||||
m_32apsk[16].re = (short)((r2*cos(M_PI/12.0))*CP);
|
||||
m_32apsk[16].im = (short)((r2*sin(M_PI/12.0))*CP);
|
||||
m_32apsk[17].re = (short)((r1*cos(M_PI/4.0))*CP);
|
||||
m_32apsk[17].im = (short)((r1*sin(M_PI/4.0))*CP);
|
||||
m_32apsk[18].re = (short)((r2*cos(-M_PI/12.0))*CP);
|
||||
m_32apsk[18].im = (short)((r2*sin(-M_PI/12.0))*CP);
|
||||
m_32apsk[19].re = (short)((r1*cos(-M_PI/4.0))*CP);
|
||||
m_32apsk[19].im = (short)((r1*sin(-M_PI/4.0))*CP);
|
||||
m_32apsk[20].re = (short)((r2*cos(11*M_PI/12.0))*CP);
|
||||
m_32apsk[20].im = (short)((r2*sin(11*M_PI/12.0))*CP);
|
||||
m_32apsk[21].re = (short)((r1*cos(3*M_PI/4.0))*CP);
|
||||
m_32apsk[21].im = (short)((r1*sin(3*M_PI/4.0))*CP);
|
||||
m_32apsk[22].re = (short)((r2*cos(-11*M_PI/12.0))*CP);
|
||||
m_32apsk[22].im = (short)((r2*sin(-11*M_PI/12.0))*CP);
|
||||
m_32apsk[23].re = (short)((r1*cos(-3*M_PI/4.0))*CP);
|
||||
m_32apsk[23].im = (short)((r1*sin(-3*M_PI/4.0))*CP);
|
||||
m_32apsk[24].re = (short)((r3*cos(0.0))*CP);
|
||||
m_32apsk[24].im = (short)((r3*sin(0.0))*CP);
|
||||
m_32apsk[25].re = (short)((r3*cos(M_PI/4.0))*CP);
|
||||
m_32apsk[25].im = (short)((r3*sin(M_PI/4.0))*CP);
|
||||
m_32apsk[26].re = (short)((r3*cos(-M_PI/8.0))*CP);
|
||||
m_32apsk[26].im = (short)((r3*sin(-M_PI/8.0))*CP);
|
||||
m_32apsk[27].re = (short)((r3*cos(-3*M_PI/8.0))*CP);
|
||||
m_32apsk[27].im = (short)((r3*sin(-3*M_PI/8.0))*CP);
|
||||
m_32apsk[28].re = (short)((r3*cos(7*M_PI/8.0))*CP);
|
||||
m_32apsk[28].im = (short)((r3*sin(7*M_PI/8.0))*CP);
|
||||
m_32apsk[29].re = (short)((r3*cos(5*M_PI/8.0))*CP);
|
||||
m_32apsk[29].im = (short)((r3*sin(5*M_PI/8.0))*CP);
|
||||
m_32apsk[30].re = (short)((r3*cos(M_PI))*CP);
|
||||
m_32apsk[30].im = (short)((r3*sin(M_PI))*CP);
|
||||
m_32apsk[31].re = (short)((r3*cos(-3*M_PI/4.0))*CP);
|
||||
m_32apsk[31].im = (short)((r3*sin(-3*M_PI/4.0))*CP);
|
||||
}
|
332
plugins/channeltx/moddatv/dvb-s2/dvbs2_physical.cpp
Normal file
332
plugins/channeltx/moddatv/dvb-s2/dvbs2_physical.cpp
Normal file
@ -0,0 +1,332 @@
|
||||
#include "DVBS2.h"
|
||||
|
||||
void DVBS2::b_64_7_code( unsigned char in, int *out )
|
||||
{
|
||||
unsigned long temp,bit;
|
||||
|
||||
temp = 0;
|
||||
|
||||
if(in&0x40) temp ^= g[0];
|
||||
if(in&0x20) temp ^= g[1];
|
||||
if(in&0x10) temp ^= g[2];
|
||||
if(in&0x08) temp ^= g[3];
|
||||
if(in&0x04) temp ^= g[4];
|
||||
if(in&0x02) temp ^= g[5];
|
||||
|
||||
bit = 0x80000000;
|
||||
for( int m = 0; m < 32; m++ )
|
||||
{
|
||||
out[(m*2)] = (temp&bit)?1:0;
|
||||
out[(m*2)+1] = out[m*2]^(in&0x01);
|
||||
bit >>= 1;
|
||||
}
|
||||
// Randomise it
|
||||
for( int m = 0; m < 64; m++ )
|
||||
{
|
||||
out[m] = out[m] ^ ph_scram_tab[m];
|
||||
}
|
||||
}
|
||||
//[MODCOD 6:2 ][TYPE 1:0 ]
|
||||
void DVBS2::s2_pl_header_encode( u8 modcod, u8 type, int *out)
|
||||
{
|
||||
unsigned char code;
|
||||
|
||||
code = (modcod<<2) | type;
|
||||
//printf("MODCOD %d TYPE %d %d\n",modcod,type,code);
|
||||
// Add the modcod and type information and scramble it
|
||||
b_64_7_code( code, out );
|
||||
}
|
||||
void DVBS2::s2_pl_header_create(void)
|
||||
{
|
||||
int type, modcod;
|
||||
|
||||
modcod = 0;
|
||||
|
||||
if( m_format[0].frame_type == FRAME_NORMAL )
|
||||
type = 0;
|
||||
else
|
||||
type = 2;
|
||||
|
||||
if( m_format[0].pilots ) type |= 1;
|
||||
|
||||
// Mode and code rate
|
||||
if( m_format[0].constellation == M_QPSK )
|
||||
{
|
||||
switch( m_format[0].code_rate )
|
||||
{
|
||||
case CR_1_4:
|
||||
modcod = 1;
|
||||
break;
|
||||
case CR_1_3:
|
||||
modcod = 2;
|
||||
break;
|
||||
case CR_2_5:
|
||||
modcod = 3;
|
||||
break;
|
||||
case CR_1_2:
|
||||
modcod = 4;
|
||||
break;
|
||||
case CR_3_5:
|
||||
modcod = 5;
|
||||
break;
|
||||
case CR_2_3:
|
||||
modcod = 6;
|
||||
break;
|
||||
case CR_3_4:
|
||||
modcod = 7;
|
||||
break;
|
||||
case CR_4_5:
|
||||
modcod = 8;
|
||||
break;
|
||||
case CR_5_6:
|
||||
modcod = 9;
|
||||
break;
|
||||
case CR_8_9:
|
||||
modcod = 10;
|
||||
break;
|
||||
case CR_9_10:
|
||||
modcod = 11;
|
||||
break;
|
||||
default:
|
||||
modcod = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( m_format[0].constellation == M_8PSK )
|
||||
{
|
||||
switch( m_format[0].code_rate )
|
||||
{
|
||||
case CR_3_5:
|
||||
modcod = 12;
|
||||
break;
|
||||
case CR_2_3:
|
||||
modcod = 13;
|
||||
break;
|
||||
case CR_3_4:
|
||||
modcod = 14;
|
||||
break;
|
||||
case CR_5_6:
|
||||
modcod = 15;
|
||||
break;
|
||||
case CR_8_9:
|
||||
modcod = 16;
|
||||
break;
|
||||
case CR_9_10:
|
||||
modcod = 17;
|
||||
break;
|
||||
default:
|
||||
modcod = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( m_format[0].constellation == M_16APSK )
|
||||
{
|
||||
switch( m_format[0].code_rate )
|
||||
{
|
||||
case CR_2_3:
|
||||
modcod = 18;
|
||||
break;
|
||||
case CR_3_4:
|
||||
modcod = 19;
|
||||
break;
|
||||
case CR_4_5:
|
||||
modcod = 20;
|
||||
break;
|
||||
case CR_5_6:
|
||||
modcod = 21;
|
||||
break;
|
||||
case CR_8_9:
|
||||
modcod = 22;
|
||||
break;
|
||||
case CR_9_10:
|
||||
modcod = 23;
|
||||
break;
|
||||
default:
|
||||
modcod = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( m_format[0].constellation == M_32APSK )
|
||||
{
|
||||
switch( m_format[0].code_rate )
|
||||
{
|
||||
case CR_3_4:
|
||||
modcod = 24;
|
||||
break;
|
||||
case CR_4_5:
|
||||
modcod = 25;
|
||||
break;
|
||||
case CR_5_6:
|
||||
modcod = 26;
|
||||
break;
|
||||
case CR_8_9:
|
||||
modcod = 27;
|
||||
break;
|
||||
case CR_9_10:
|
||||
modcod = 28;
|
||||
break;
|
||||
default:
|
||||
modcod = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Now create the PL header.
|
||||
int b[90];
|
||||
// Add the sync sequence SOF
|
||||
for( int i = 0; i < 26; i++ ) b[i] = ph_sync_seq[i];
|
||||
// Add the mode and code
|
||||
s2_pl_header_encode( modcod, type, &b[26] );
|
||||
|
||||
// BPSK modulate and add the header
|
||||
for( int i = 0; i < 90; i++ )
|
||||
{
|
||||
m_pl[i] = m_bpsk[i&1][b[i]];
|
||||
}
|
||||
}
|
||||
//
|
||||
// m_symbols is the total number of complex symbols in the frame
|
||||
// Modulate the data starting at symbol 90
|
||||
//
|
||||
int DVBS2::s2_pl_data_pack( void )
|
||||
{
|
||||
int m = 0;
|
||||
int n = 90;// Jump over header
|
||||
int blocks = m_payload_symbols/90;
|
||||
int block_count = 0;
|
||||
|
||||
// See if PSK
|
||||
if( m_format[0].constellation == M_QPSK )
|
||||
{
|
||||
for( int i = 0; i < blocks; i++ )
|
||||
{
|
||||
for( int j = 0; j < 90; j++ )
|
||||
{
|
||||
m_pl[n++] = m_qpsk[m_iframe[m++]&0x3];
|
||||
}
|
||||
block_count = (block_count+1)%16;
|
||||
if((block_count == 0)&&(i<blocks-1))
|
||||
{
|
||||
if( m_format[0].pilots )
|
||||
{
|
||||
// Add pilots if needed
|
||||
for( int k = 0; k < 36; k++ )
|
||||
{
|
||||
m_pl[n++] = m_bpsk[0][0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// See if 8 PSK
|
||||
if( m_format[0].constellation == M_8PSK )
|
||||
{
|
||||
for( int i = 0; i < blocks; i++ )
|
||||
{
|
||||
for( int j = 0; j < 90; j++ )
|
||||
{
|
||||
m_pl[n++] = m_8psk[m_iframe[m++]&0x7];
|
||||
}
|
||||
block_count = (block_count+1)%16;
|
||||
if((block_count == 0)&&(i<blocks-1))
|
||||
{
|
||||
if( m_format[0].pilots )
|
||||
{
|
||||
// Add pilots if needed
|
||||
for( int k = 0; k < 36; k++ )
|
||||
{
|
||||
m_pl[n++] = m_bpsk[0][0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// See if 16 PSK
|
||||
if( m_format[0].constellation == M_16APSK )
|
||||
{
|
||||
for( int i = 0; i < blocks; i++ )
|
||||
{
|
||||
for( int j = 0; j < 90; j++ )
|
||||
{
|
||||
m_pl[n++] = m_16apsk[m_iframe[m++]&0xF];
|
||||
}
|
||||
block_count = (block_count+1)%16;
|
||||
if((block_count == 0)&&(i<blocks-1))
|
||||
{
|
||||
if( m_format[0].pilots )
|
||||
{
|
||||
// Add pilots if needed
|
||||
for( int k = 0; k < 36; k++ )
|
||||
{
|
||||
m_pl[n++] = m_bpsk[0][0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// See if 32 APSK
|
||||
if( m_format[0].constellation == M_32APSK )
|
||||
{
|
||||
for( int i = 0; i < blocks; i++ )
|
||||
{
|
||||
for( int j = 0; j < 90; j++ )
|
||||
{
|
||||
m_pl[n++] = m_32apsk[m_iframe[m++]&0x1F];
|
||||
}
|
||||
block_count = (block_count+1)%16;
|
||||
if((block_count == 0)&&(i<blocks-1))
|
||||
{
|
||||
if( m_format[0].pilots )
|
||||
{
|
||||
// Add pilots if needed
|
||||
for( int k = 0; k < 36; k++ )
|
||||
{
|
||||
m_pl[n++] = m_bpsk[0][0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Now apply the scrambler to the data part not the header
|
||||
pl_scramble_symbols( &m_pl[90], n - 90 );
|
||||
// Return the length
|
||||
return n;
|
||||
}
|
||||
//
|
||||
// This is not used for Broadcast mode
|
||||
//
|
||||
void DVBS2::pl_build_dummy( void )
|
||||
{
|
||||
int n = 0;
|
||||
int b[90];
|
||||
|
||||
// Add the sync sequence SOF
|
||||
for( int i = 0; i < 26; i++ ) b[i] = ph_sync_seq[i];
|
||||
// Add the mode and code and sync sequence
|
||||
s2_pl_header_encode( 0, 0, &b[26] );
|
||||
// BPSK Modulate
|
||||
for( int i = 0; i < 90; i++ )
|
||||
{
|
||||
m_pl[i].re = m_bpsk[i&1][b[i]].re;
|
||||
m_pl[i].im = m_bpsk[i&1][b[i]].im;
|
||||
}
|
||||
n += (90*36);
|
||||
pl_scramble_dummy_symbols( n );
|
||||
m_dummy_frame_length = n;
|
||||
}
|
||||
|
||||
scmplx * DVBS2::pl_get_frame( void )
|
||||
{
|
||||
return m_pl;
|
||||
}
|
||||
|
||||
scmplx * DVBS2::pl_get_dummy( int &len )
|
||||
{
|
||||
scmplx * frame;
|
||||
|
||||
len = m_dummy_frame_length;
|
||||
frame = m_pl_dummy;
|
||||
return frame;
|
||||
}
|
110
plugins/channeltx/moddatv/dvb-s2/dvbs2_scrambler.cpp
Normal file
110
plugins/channeltx/moddatv/dvb-s2/dvbs2_scrambler.cpp
Normal file
@ -0,0 +1,110 @@
|
||||
#include "DVBS2.h"
|
||||
|
||||
int DVBS2::parity_chk( long a, long b)
|
||||
{
|
||||
int c = 0;
|
||||
a = a & b;
|
||||
for( int i = 0; i < 18; i++ )
|
||||
{
|
||||
if( a&(1L<<i)) c++;
|
||||
}
|
||||
return c&1;
|
||||
}
|
||||
//
|
||||
// This is not time sensitive and is only run at start up
|
||||
//
|
||||
void DVBS2::build_symbol_scrambler_table( void )
|
||||
{
|
||||
long x,y;
|
||||
int xa,xb,xc,ya,yb,yc;
|
||||
int rn,zna,znb;
|
||||
|
||||
// Initialisation
|
||||
x = 0x00001;
|
||||
y = 0x3FFFF;
|
||||
|
||||
for( int i = 0; i < FRAME_SIZE_NORMAL; i++ )
|
||||
{
|
||||
xa = parity_chk( x, 0x8050 );
|
||||
xb = parity_chk( x, 0x0081 );
|
||||
xc = x&1;
|
||||
|
||||
x >>= 1;
|
||||
if( xb ) x |= 0x20000;
|
||||
|
||||
ya = parity_chk( y, 0x04A1 );
|
||||
yb = parity_chk( y, 0xFF60 );
|
||||
yc = y&1;
|
||||
|
||||
y >>= 1;
|
||||
if( ya ) y |= 0x20000;
|
||||
|
||||
zna = xc ^ yc;
|
||||
znb = xa ^ yb;
|
||||
rn = (znb<<1) + zna;
|
||||
m_cscram[i] = rn;
|
||||
}
|
||||
}
|
||||
|
||||
void DVBS2::pl_scramble_symbols( scmplx *fs, int len )
|
||||
{
|
||||
scmplx x;
|
||||
|
||||
// Start at the end of the PL Header.
|
||||
|
||||
for( int n = 0; n < len; n++ )
|
||||
{
|
||||
switch( m_cscram[n] )
|
||||
{
|
||||
case 0:
|
||||
// Do nothing
|
||||
break;
|
||||
case 1:
|
||||
x = fs[n];
|
||||
fs[n].re = -x.im;
|
||||
fs[n].im = x.re;
|
||||
break;
|
||||
case 2:
|
||||
fs[n].re = -fs[n].re;
|
||||
fs[n].im = -fs[n].im;
|
||||
break;
|
||||
case 03:
|
||||
x = fs[n];
|
||||
fs[n].re = x.im;
|
||||
fs[n].im = -x.re;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void DVBS2::pl_scramble_dummy_symbols( int len )
|
||||
{
|
||||
scmplx x;
|
||||
int p = 0;
|
||||
|
||||
x = m_bpsk[0][0];
|
||||
|
||||
for( int n = 90; n < len; n++ )
|
||||
{
|
||||
switch( m_cscram[p] )
|
||||
{
|
||||
case 0:
|
||||
// Do nothing
|
||||
m_pl_dummy[n].re = x.re;
|
||||
m_pl_dummy[n].im = x.im;
|
||||
break;
|
||||
case 1:
|
||||
m_pl_dummy[n].re = -x.im;
|
||||
m_pl_dummy[n].im = x.re;
|
||||
break;
|
||||
case 2:
|
||||
m_pl_dummy[n].re = -x.re;
|
||||
m_pl_dummy[n].im = -x.im;
|
||||
break;
|
||||
case 3:
|
||||
m_pl_dummy[n].re = x.im;
|
||||
m_pl_dummy[n].im = -x.re;
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
19
plugins/channeltx/moddatv/dvb-s2/dvbs2_tables.cpp
Normal file
19
plugins/channeltx/moddatv/dvb-s2/dvbs2_tables.cpp
Normal file
@ -0,0 +1,19 @@
|
||||
#include "DVBS2.h"
|
||||
//
|
||||
// Modcod error correction
|
||||
//
|
||||
|
||||
const unsigned long DVBS2::g[6]=
|
||||
{
|
||||
0x55555555,0x33333333,0x0F0F0F0F,0x00FF00FF,0x0000FFFF,0xFFFFFFFF
|
||||
};
|
||||
|
||||
const int DVBS2::ph_scram_tab[64]=
|
||||
{
|
||||
0,1,1,1,0,0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,0,0,1,1,1,1,0,0,1,0,0,1,
|
||||
0,1,0,1,0,0,1,1,0,1,0,0,0,0,1,0,0,0,1,0,1,1,0,1,1,1,1,1,1,0,1,0
|
||||
};
|
||||
const int DVBS2::ph_sync_seq[26]=
|
||||
{
|
||||
0,1,1,0,0,0,1,1,0,1,0,0,1,0,1,1,1,0,1,0,0,0,0,0,1,0
|
||||
};
|
1
plugins/channeltx/moddatv/dvb-s2/readme.md
Normal file
1
plugins/channeltx/moddatv/dvb-s2/readme.md
Normal file
@ -0,0 +1 @@
|
||||
This DVB-S2 code is from https://github.com/G4GUO/
|
@ -2,7 +2,7 @@
|
||||
|
||||
<h2>Introduction</h2>
|
||||
|
||||
This plugin can be used to transmit a digital amateur TV signal in the DVB-S standard. The plugin requires the video and audio to be transmitted to be in an MPEG transport stream.
|
||||
This plugin can be used to transmit a digital amateur TV signal in the DVB-S or DVB-S2 standards. The plugin requires the video and audio to be transmitted to be in an MPEG transport stream.
|
||||
The MPEG transport stream can either be read from a file or streamed via UDP.
|
||||
|
||||
The MPEG transport stream must (for now) be created outside of SDRangel, using software such as ffmpeg. The MPEG transport stream can contain video compressed using codecs such as MPEG-2, h264 or h265 (HEVC).
|
||||
@ -11,6 +11,8 @@ The DATV modulator plugin just performs channel coding and modulation of the tra
|
||||
|
||||
DVB-S includes: scrambling, Reed-Solomon RS(204,188,T=8) coding, convolutional interleaving (I=12), convolutional encoding (code rate=1/2, with optional puncturing to rates of 2/3, 3/4, 5/6 and 7/8) and BPSK or QPSK modulation.
|
||||
|
||||
DVB-S2 includes: scrambling, BCH encoder, LDPC encoder, bit interleaver and QPSK, 8PSK, 16APSK or 32APSK modulation.
|
||||
|
||||
<h2>Interface</h2>
|
||||
|
||||
![DATV Modulator plugin GUI](../../../doc/img/DATVMod_plugin.png)
|
||||
@ -44,7 +46,7 @@ Use this button to toggle mute for this channel. The radio waves on the icon are
|
||||
|
||||
<h3>6: Standard</h3>
|
||||
|
||||
Select the DVB standard to use for channel coding and modulation. Currenty only DVB-S is supported.
|
||||
Select the DVB standard to use for channel coding and modulation. This can be either DVB-S or DVB-S2.
|
||||
|
||||
<h3>7: Symbol rate</h3>
|
||||
|
||||
@ -67,15 +69,17 @@ When using UDP, the packet size should be an integer multiple of the MPEG transp
|
||||
|
||||
Forward error correction code rate. This controls the number of bits sent to help the receiver to correct errors.
|
||||
A code rate of 1/2 has the highest overhead (corresponding to a lower data rate), but allows the most amount of errors to be correct.
|
||||
7/8 has the least overhead (corresponding to higher data rates), but will allow the fewest amount of errors to be corrected.
|
||||
7/8 (DVB-S) or 9/10 (DVB-S2) has the least overhead (corresponding to higher data rates), but will allow the fewest amount of errors to be corrected.
|
||||
|
||||
<h3>11: Modulation</h3>
|
||||
|
||||
Select the modulation to be used. This can either be BPSK or QPSK. BPSK transmits a single bit per symbol, whereas QPSK transmits two bits per symbol, so has twice the bitrate.
|
||||
Select the modulation to be used. For DVB-S, this can either be BPSK or QPSK. For DVB-S2, this can be QPSK, 8PSK, 16APSK or 32PSK.
|
||||
|
||||
BPSK transmits a single bit per symbol, whereas QPSK transmits two bits per symbol, so has twice the bitrate. Similar, 8PSK is 3 bits per symbol, 16APSK 4 and 32PSK 5. BPSK, QPSK and 8PSK only modulate phase. 16APSK and 32APKS modulate both phase and amplitude.
|
||||
|
||||
<h3>12: Roll off</h3>
|
||||
|
||||
Roll-off for the root raised cosine filter. For DVB-S, this should be 0.35.
|
||||
Roll-off for the root raised cosine filter. For DVB-S, this should be 0.35. For DVB-S2 this can be 0.2, 0.25 or 0.35.
|
||||
|
||||
<h3>13: UDP IP address</h3>
|
||||
|
||||
@ -121,11 +125,11 @@ This slider can be used to randomly set the current position in the file when fi
|
||||
|
||||
An MPEG transport stream file can be created from a video file using ffpmeg:
|
||||
|
||||
ffmpeg -i input.avi -pix_fmt yuv420p -r 25 -s 720x576 -aspect 4:3 -c:v hevc -c:a libopus -b:v 500k -b:a 64k -maxrate 600k -bufsize 50k -f mpegts -mpegts_original_network_id 1 -mpegts_transport_stream_id 1 -mpegts_service_id 1 -mpegts_pmt_start_pid 4096 -streamid 0:289 -streamid 1:337 -metadata service_provider="SDRangel" -metadata service_name="SDRangel TV" -y mpeg.ts
|
||||
ffmpeg -i input.avi -pix_fmt yuv420p -r 25 -s 720x576 -aspect 4:3 -c:v hevc -c:a libopus -b:v 500k -b:a 64k -maxrate 600k -bufsize 50k -f mpegts -mpegts_original_network_id 1 -mpegts_transport_stream_id 1 -mpegts_service_id 1 -mpegts_pmt_start_pid 4096 -streamid 0:289 -streamid 1:337 -metadata service_provider="SDRangel" -metadata service_name="SDRangel TV" -y mpeg.ts
|
||||
|
||||
To stream from a video camera via UDP (on Windows):
|
||||
|
||||
ffmpeg -f dshow -i video="c922 Pro Stream Webcam":audio="Microphone (C922 Pro Stream Webcam)" -pix_fmt yuv420p -r 25 -s 720x576 -aspect 4:3 -c:v hevc -c:a libopus -b:v 500k -b:a 64k -maxrate 600k -bufsize 50k -f mpegts -mpegts_original_network_id 1 -mpegts_transport_stream_id 1 -mpegts_service_id 1 -mpegts_pmt_start_pid 4096 -streamid 0:289 -streamid 1:337 -metadata service_provider="SDRangel" -metadata service_name="SDRangel TV" -flush_packets 0 "udp://127.0.0.1:5004?pkt_size=1316&bitrate=600000"
|
||||
ffmpeg -f dshow -i video="c922 Pro Stream Webcam":audio="Microphone (C922 Pro Stream Webcam)" -pix_fmt yuv420p -r 25 -s 720x576 -aspect 4:3 -c:v hevc -c:a libopus -b:v 500k -b:a 64k -maxrate 600k -bufsize 50k -f mpegts -mpegts_original_network_id 1 -mpegts_transport_stream_id 1 -mpegts_service_id 1 -mpegts_pmt_start_pid 4096 -streamid 0:289 -streamid 1:337 -metadata service_provider="SDRangel" -metadata service_name="SDRangel TV" -flush_packets 0 "udp://127.0.0.1:5004?pkt_size=1316&bitrate=600000"
|
||||
|
||||
You can list camera devices with:
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user