diff options
author | Lars Heer <l.heer@gmx.de> | 2013-09-18 05:50:03 +0200 |
---|---|---|
committer | Lars Heer <l.heer@gmx.de> | 2013-09-18 05:50:03 +0200 |
commit | ccf6e0f9c6b0481ed13e0f4794e3fbead750f385 (patch) | |
tree | ed86efb54f7ee41edfba5c89ca519b5fd10aa0d5 /device.c | |
download | vdr-plugin-mcli-ccf6e0f9c6b0481ed13e0f4794e3fbead750f385.tar.gz vdr-plugin-mcli-ccf6e0f9c6b0481ed13e0f4794e3fbead750f385.tar.bz2 |
added vdr-plugin-mcli-0.0.1+svn20120927
Diffstat (limited to 'device.c')
-rw-r--r-- | device.c | 962 |
1 files changed, 962 insertions, 0 deletions
diff --git a/device.c b/device.c new file mode 100644 index 0000000..2acabe0 --- /dev/null +++ b/device.c @@ -0,0 +1,962 @@ +/* + * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de + * + * See the COPYING file for copyright information and + * how to reach the author. + * + */ + +#include <time.h> +#include <iostream> + +#include <vdr/channels.h> +#include <vdr/ringbuffer.h> +#include <vdr/eit.h> +#include <vdr/timers.h> +#include <vdr/skins.h> +#include <vdr/eitscan.h> + +#include "filter.h" +#include "device.h" +#include "mcli.h" + +#define st_Pos 0x07FF +#define st_Neg 0x0800 + +using namespace std; + +static int handle_ts (unsigned char *buffer, size_t len, void *p) +{ + return p ? ((cMcliDevice *) p)->HandleTsData (buffer, len) : len; +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +static int handle_ten (tra_t * ten, void *p) +{ + cMcliDevice *m = (cMcliDevice *) p; + if (ten) { +// fprintf (stderr, "Status:%02X, Strength:%04X, SNR:%04X, BER:%04X\n", ten->s.st, ten->s.strength, ten->s.snr, ten->s.ber); + m->SetTenData (ten); + if (ten->s.st & FE_HAS_LOCK) { + m->m_locked.Broadcast (); + } + } else { + tra_t ten; + memset (&ten, 0, sizeof (tra_t)); + m->SetTenData (&ten); +// fprintf (stderr, "Signal lost\n"); + } + return 0; +} + +cMcliDevice::cMcliDevice (void) +{ + m_enable = false; + m_tuned = false; + StartSectionHandler (); +#ifdef USE_VDR_PACKET_BUFFER + m_PB = new cRingBufferLinear(MEGABYTE(4), TS_SIZE, false, "MCLI_TS"); + m_PB->SetTimeouts (0, 100); + delivered = false; +#else + m_PB = new cMyPacketBuffer (10000 * TS_SIZE, 10000); + m_PB->SetTimeouts (0, CLOCKS_PER_SEC * 20 / 1000); +#endif + m_filters = new cMcliFilters (); +// printf ("cMcliDevice: got device number %d\n", CardIndex () + 1); + m_pidsnum = 0; + m_mcpidsnum = 0; + m_filternum = 0; + m_mcli = NULL; + m_fetype = -1; + m_last = 0; + m_showtuning = 0; + m_ca_enable = false; + m_ca_override = false; + memset (m_pids, 0, sizeof (m_pids)); + memset (&m_ten, 0, sizeof (tra_t)); + m_pids[0].pid=-1; + m_disabletimeout = TEMP_DISABLE_TIMEOUT_DEFAULT; + m_tunerref = NULL; + m_camref = NULL; + InitMcli (); +} + +cMcliDevice::~cMcliDevice () +{ + LOCK_THREAD; + StopSectionHandler (); + printf ("Device %d gets destructed\n", CardIndex () + 1); + Cancel (0); + m_locked.Broadcast (); + ExitMcli (); + DELETENULL (m_filters); + DELETENULL (m_PB); +} + +bool cMcliDevice::Ready() { + return m_mcli ? m_mcli->Ready() : false; +} + +void cMcliDevice::SetTenData (tra_t * ten) +{ + if(!ten->lastseen) { + ten->lastseen=m_ten.lastseen; + } + m_ten = *ten; +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +void cMcliDevice::SetEnable (bool val) +{ + LOCK_THREAD; + m_enable = val; + if (!m_enable) { + recv_stop (m_r); + m_tuned = false; + if(GetCaEnable()) { + SetCaEnable(false); + m_mcli->CAMFree(m_camref); + m_camref = NULL; + } + if(m_tunerref) { + m_mcli->TunerFree(m_tunerref); + m_tunerref = NULL; + m_fetype = -1; + } + } else { + if(m_tunerref == NULL) { +#if VDRVERSNUM < 10702 + bool s2=m_chan.Modulation() == QPSK_S2 || m_chan.Modulation() == PSK8; +#elif VDRVERSNUM < 10714 + bool s2=m_chan.System() == SYS_DVBS2; +#else + cDvbTransponderParameters dtp(m_chan.Parameters()); + bool s2=dtp.System() == SYS_DVBS2; +#endif + bool ret = false; + int pos; + int type; + + TranslateTypePos(type, pos, m_chan.Source()); + if(s2) { + type=FE_DVBS2; + } + ret = m_mcli->TunerAvailable((fe_type_t)type, pos); + if(!ret && type == FE_QPSK) { + type = FE_DVBS2; + ret = m_mcli->TunerAvailable((fe_type_t)type, pos); + } + if(!ret) { + return; + } + m_fetype = type; + + int slot = -1; + if(m_chan.Ca(0)<=0xff) { + slot=m_chan.Ca(0)&0x03; + if(slot) { + slot--; + } + } + + if(m_chan.Ca() && !GetCaEnable() && m_mcli->CAMAvailable(NULL, slot) && (m_camref=m_mcli->CAMAlloc(NULL, slot))) { + SetCaEnable(); + } + + recv_tune (m_r, (fe_type_t)m_fetype, m_pos, &m_sec, &m_fep, m_pids); + m_tuned = true; + } + } +} + +bool cMcliDevice::SetTempDisable (bool now) +{ + if(!now) { + Lock(); + } +//#ifndef REELVDR // they might find it out in some other place + // Check for tuning timeout + if(m_showtuning && Receiving(true) && ((time(NULL)-m_ten.lastseen)>=LASTSEEN_TIMEOUT)) { + Skins.QueueMessage(mtInfo, cString::sprintf(tr("Waiting for a free tuner (%s)"),m_chan.Name())); + m_showtuning = false; + } +//#endif +// printf("Device %d Receiving %d Priority %d\n",CardIndex () + 1, Receiving (true), Priority()); + if(!Receiving (true) && (((time(NULL)-m_last) >= m_disabletimeout)) || now) { + recv_stop (m_r); + m_tuned = false; + if(GetCaEnable()) { + SetCaEnable(false); +#ifdef DEBUG_TUNE + printf("Releasing CAM on %d (%s) (disable, %d)\n",CardIndex()+1, m_chan.Name(), now); +#endif + m_mcli->CAMFree(m_camref); + m_camref = NULL; + } + if(m_tunerref) { +#ifdef DEBUG_TUNE + printf("Releasing tuner on %d (%s)\n",CardIndex()+1, m_chan.Name()); +#endif + m_mcli->TunerFree(m_tunerref, false); + m_tunerref = NULL; + m_fetype = -1; + } + if(!now) { + Unlock(); + } + return true; + } + if(!now) { + Unlock(); + } + return false; +} + +void cMcliDevice::SetFEType (fe_type_t val) +{ + m_fetype = (int)val; +} + +int cMcliDevice::HandleTsData (unsigned char *buffer, size_t len) +{ +#ifdef USE_VDR_PACKET_BUFFER + cMutexLock lock (&m_PB_Lock); +#endif + m_filters->PutTS (buffer, len); +#ifdef GET_TS_PACKETS + unsigned char *ptr = m_PB->PutStart (len); + if (ptr) { + memcpy (ptr, buffer, len); + m_PB->PutEnd (len, 0, 0); + } +#else +#ifdef USE_VDR_PACKET_BUFFER + if(m_PB->Free() < len) { + m_PB->Clear(); + if(Receiving(true)) isyslog("MCLI: HandleTsData buffer overflow [%d] %s", CardIndex()+1, m_chan.Name()); + } + return m_PB->Put(buffer, len); +#else + unsigned int i; + for (i = 0; i < len; i += TS_SIZE) { + unsigned char *ptr = m_PB->PutStart (TS_SIZE); + if (ptr) { + memcpy (ptr, buffer + i, TS_SIZE); + m_PB->PutEnd (TS_SIZE, 0, 0); + } + } +#endif +#endif + return len; +} + + +void cMcliDevice::InitMcli (void) +{ + m_r = recv_add (); + + register_ten_handler (m_r, handle_ten, this); + register_ts_handler (m_r, handle_ts, this); +} + +void cMcliDevice::ExitMcli (void) +{ + register_ten_handler (m_r, NULL, NULL); + register_ts_handler (m_r, NULL, NULL); + recv_del (m_r); + m_r = NULL; +} + +bool cMcliDevice::ProvidesSource (int Source) const +{ + int pos; + int type; + bool ret=false; + + if (!m_enable) { + return false; + } + + TranslateTypePos(type, pos, Source); + + if(m_tunerref) { + ret= (type == m_fetype) || (type == FE_QPSK && m_fetype == FE_DVBS2); + if(ret) { + ret = m_mcli->TunerSatelitePositionLookup(m_tunerref, pos); + } + } + + if(!ret) { + ret = m_mcli->TunerAvailable((fe_type_t)type, pos); + if(!ret && type == FE_QPSK) { + type = FE_DVBS2; + ret = m_mcli->TunerAvailable((fe_type_t)type, pos); + } + } +#ifdef DEBUG_TUNE_EXTRA + printf ("ProvidesSource:%d Type:%d Pos:%d -> %d\n", CardIndex () + 1, type, pos, ret); +#endif + return ret; +} + +bool cMcliDevice::ProvidesTransponder (const cChannel * Channel) const +{ + if (!m_enable) { + return false; + } +#if VDRVERSNUM < 10702 + bool s2=Channel->Modulation() == QPSK_S2 || Channel->Modulation() == PSK8; +#elif VDRVERSNUM < 10714 + bool s2=Channel->System() == SYS_DVBS2; +#else + cDvbTransponderParameters dtp(Channel->Parameters()); + bool s2=dtp.System() == SYS_DVBS2; +#endif + bool ret=ProvidesSource (Channel->Source ()); + if(ret) { + int pos; + int type; + TranslateTypePos(type, pos, Channel->Source()); + if(s2) { + type=FE_DVBS2; + } + if(m_tunerref) { + ret = (m_fetype == type) || (type == FE_QPSK && m_fetype == FE_DVBS2); + } else { + ret = false; + } + if(!ret) { + ret = m_mcli->TunerAvailable((fe_type_t)type, pos); + if(!ret && type == FE_QPSK) { + type = FE_DVBS2; + ret = m_mcli->TunerAvailable((fe_type_t)type, pos); + } + } + } +#ifdef DEBUG_TUNE_EXTRA + printf ("ProvidesTransponder:%d S2:%d %s@%p -> %d\n", CardIndex () + 1, s2, Channel->Name (), this, ret); +#endif + return ret; +} + +bool cMcliDevice::IsTunedToTransponderConst (const cChannel * Channel) const +{ +// printf ("IsTunedToTransponder %s == %s \n", Channel->Name (), m_chan.Name ()); + if (!m_enable || !m_tuned) { + return false; + } + +#if VDRVERSNUM > 10713 + cDvbTransponderParameters m_dtp(m_chan.Parameters()); + cDvbTransponderParameters dtp(Channel->Parameters()); +#endif + + if (m_ten.s.st & FE_HAS_LOCK && m_chan.Source() == Channel->Source() && + m_chan.Transponder() == Channel->Transponder() && m_chan.Frequency() == Channel->Frequency() && +#if VDRVERSNUM > 10713 + m_dtp.Modulation() == dtp.Modulation() && +#else + m_chan.Modulation() == Channel->Modulation() && +#endif + m_chan.Srate() == Channel->Srate()) { +// printf ("Yes!!!"); + return true; + } +// printf ("Nope!!!"); + return false; +} + +bool cMcliDevice::IsTunedToTransponder (const cChannel * Channel) +{ + return IsTunedToTransponderConst(Channel); +} + +bool cMcliDevice::CheckCAM(const cChannel * Channel, bool steal) const +{ + if(GetCaOverride() || !Channel->Ca()) { + return true; + } + int slot = -1; + if(Channel->Ca(0)<=0xff) { + slot=Channel->Ca(0)&0x03; + if(slot) { + slot--; + } + } + if(m_camref && (m_camref->slot == slot || slot == -1)) { + return true; + } + if(!m_mcli->CAMAvailable(NULL, slot) && !m_mcli->CAMSteal(NULL, slot, steal)) { + return false; + } + return true; +} + +bool cMcliDevice::ProvidesChannel (const cChannel * Channel, int Priority, bool * NeedsDetachReceivers) const +{ + bool result = false; + bool hasPriority = Priority < 0 || Priority > this->Priority (); + bool needsDetachReceivers = false; + if (!m_enable) { + return false; + } + if(!CheckCAM(Channel, false)) { +#ifdef DEBUG_TUNE + printf ("ProvidesChannel:%d Channel:%s, Prio:%d this->Prio:%d m_chan.Name:%s -> %d\n", CardIndex () + 1, Channel->Name (), Priority, this->Priority (), m_chan.Name(), false); +#endif + return false; + } + if(ProvidesTransponder(Channel)) { + result = hasPriority; + if (Priority >= 0 && Receiving (true)) + { + if (!IsTunedToTransponderConst(Channel)) { + needsDetachReceivers = true; + } else { + result = true; + } + } + } +#ifdef DEBUG_TUNE + printf ("ProvidesChannel:%d Channel:%s, Prio:%d this->Prio:%d m_chan.Name:%s NeedsDetachReceivers:%d -> %d\n", CardIndex () + 1, Channel->Name (), Priority, this->Priority (), m_chan.Name(), needsDetachReceivers, result); +#endif + if (NeedsDetachReceivers) { + *NeedsDetachReceivers = needsDetachReceivers; + } + return result; +} + +void cMcliDevice::TranslateTypePos(int &type, int &pos, const int Source) const +{ +#if VDRVERSNUM < 10713 + pos = Source; + pos = ((pos & st_Neg) ? 1 : -1) * (pos & st_Pos); +#else + int n = (Source & 0xffff); + + if (n > 0x00007FFF) { + n |= 0xFFFF0000; + } + + pos=abs(n); + + if (n > 0 ){ + pos = -pos; + } +#endif + if (pos) { + pos += 1800; + } else { + pos = NO_SAT_POS; + } + + type = Source & cSource::st_Mask; + switch(type) { + case cSource::stCable: + type = FE_QAM; + break; + case cSource::stSat: + type = FE_QPSK; + break; + case cSource::stTerr: + type = FE_OFDM; + break; + default: + type = -1; + } +} + +bool cMcliDevice::SetChannelDevice (const cChannel * Channel, bool LiveView) +{ + bool is_scan = false; + int pos; + int type; + bool s2; + + is_scan = !strlen(Channel->Name()) && !strlen(Channel->Provider()); + +#ifdef DEBUG_TUNE + printf ("SetChannelDevice:%d Channel(%p):%s, Provider:%s, Source:%d, LiveView:%s, IsScan:%d, m_chan.Name:%s\n", CardIndex () + 1, Channel, Channel->Name (), Channel->Provider (), Channel->Source (), LiveView ? "true" : "false", is_scan, m_chan.Name()); +#endif + if (!m_enable) { + return false; + } + LOCK_THREAD; + + if(is_scan) { + m_disabletimeout = TEMP_DISABLE_TIMEOUT_SCAN; + } else if (GetCaOverride()) { + m_disabletimeout = TEMP_DISABLE_TIMEOUT_CAOVERRIDE; + } else { + m_disabletimeout = TEMP_DISABLE_TIMEOUT_DEFAULT; + } + bool cam_force=!EITScanner.UsesDevice(this); + if(cam_force && !CheckCAM(Channel, true)) { +#ifdef DEBUG_TUNE + printf("No CAM on %d available even after tried to steal one\n", CardIndex () + 1); +#endif + return false; + } + + if(!GetCaOverride() && Channel->Ca() && !GetCaEnable()) { + int slot = -1; + if(Channel->Ca(0)<=0xff) { + slot=Channel->Ca(0)&0x03; + if(slot) { + slot--; + } + } + if(!(m_camref=m_mcli->CAMAlloc(NULL, slot))) { +#ifdef DEBUG_TUNE + printf("failed to get CAM on %d\n",CardIndex () + 1); +#endif + if(cam_force) { + return false; + } + } + if(m_camref) { + SetCaEnable(); + } + } + TranslateTypePos(type, pos, Channel->Source()); +#if VDRVERSNUM < 10702 + s2=Channel->Modulation() == QPSK_S2 || Channel->Modulation() == PSK8; +#elif VDRVERSNUM < 10714 + s2=Channel->System() == SYS_DVBS2; +#else + cDvbTransponderParameters dtp(Channel->Parameters()); + s2=dtp.System() == SYS_DVBS2; +#endif + if(s2) { + type = FE_DVBS2; + } + + if(m_tunerref && (FE_QPSK == type) && (FE_DVBS2 == m_fetype)) type = FE_DVBS2; + if(m_tunerref && (m_fetype != type || !m_mcli->TunerSatelitePositionLookup(m_tunerref, pos))) { + m_mcli->TunerFree(m_tunerref); + m_tunerref = NULL; + } + + if(s2 && (m_fetype != FE_DVBS2)) { + if(m_tunerref) { + m_mcli->TunerFree(m_tunerref); + m_tunerref = NULL; + } + type=FE_DVBS2; + } + + if(m_tunerref == NULL) { + m_tunerref = m_mcli->TunerAlloc((fe_type_t)type, pos); + if(m_tunerref == NULL && type == FE_QPSK) { + type = FE_DVBS2; + m_tunerref = m_mcli->TunerAlloc((fe_type_t)type, pos); + } + m_tuned = false; + if(m_tunerref == NULL) { + return false; + } + m_fetype = type; + } + + m_pos = pos; + + if (IsTunedToTransponder (Channel) && !is_scan) { + m_chan = *Channel; + +#ifdef DEBUG_TUNE + printf("Already tuned to transponder on %d\n",CardIndex () + 1); +#endif + return true; + } else { + memset (&m_ten, 0, sizeof (tra_t)); + } + memset (&m_sec, 0, sizeof (recv_sec_t)); + memset (&m_fep, 0, sizeof (struct dvb_frontend_parameters)); + m_chan = *Channel; + +// printf("Really tuning on %d\n",CardIndex () + 1); + switch (m_fetype) { + case FE_DVBS2: + case FE_QPSK:{ // DVB-S + + unsigned int frequency = Channel->Frequency (); + +#if VDRVERSNUM < 10714 + fe_sec_voltage_t volt = (Channel->Polarization () == 'v' || Channel->Polarization () == 'V' || Channel->Polarization () == 'r' || Channel->Polarization () == 'R') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18; +#else + fe_sec_voltage_t volt = (dtp.Polarization () == 'v' || dtp.Polarization () == 'V' || dtp.Polarization () == 'r' || dtp.Polarization () == 'R') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18; +#endif + m_sec.voltage = volt; + frequency =::abs (frequency); // Allow for C-band, where the frequency is less than the LOF + m_fep.frequency = frequency * 1000UL; +#if VDRVERSNUM < 10714 + m_fep.inversion = fe_spectral_inversion_t (Channel->Inversion ()); +#else + m_fep.inversion = fe_spectral_inversion_t (dtp.Inversion ()); +#endif + m_fep.u.qpsk.symbol_rate = Channel->Srate () * 1000UL; +#if VDRVERSNUM < 10702 +// m_fep.u.qpsk.fec_inner = fe_code_rate_t (Channel->CoderateH () | (Channel->Modulation () << 16)); + int modulation = Channel->Modulation (); +#if DVB_API_VERSION > 3 + if (modulation==PSK_8) // Needed if PSK_8 != PSK8 + modulation = PSK8; + else if(modulation==PSK_8+4) // patched DVB_V5 QPSK for S2 + modulation = QPSK_S2; +#endif + m_fep.u.qpsk.fec_inner = fe_code_rate_t (Channel->CoderateH () | (modulation << 16)); +#elif VDRVERSNUM < 10714 + if(s2) { + int modulation = 0; + switch(Channel->Modulation ()) { + case QPSK: + modulation = QPSK_S2; + break; + case PSK_8: + modulation = PSK8; + break; + } + m_fep.u.qpsk.fec_inner = fe_code_rate_t (Channel->CoderateH () | (modulation << 16)); + } +#else + if(s2) { + int modulation = 0; + switch(dtp.Modulation ()) { + case QPSK: + modulation = QPSK_S2; + break; + case PSK_8: + modulation = PSK8; + break; + } + int coderateH = dtp.CoderateH (); + switch(dtp.CoderateH()) { + case FEC_AUTO+1: // DVB-API 5 FEC_3_5 + coderateH = FEC_AUTO+4; // MCLI-API FEC_3_5 + break; + case FEC_AUTO+2: // DVB-API 5 FEC_9_10 + coderateH = FEC_AUTO+5; // MCLI-API FEC_9_10 + break; + } + m_fep.u.qpsk.fec_inner = fe_code_rate_t (coderateH | (modulation << 16)); + } +#endif + } + break; + case FE_QAM:{ // DVB-C + + // Frequency and symbol rate: + m_fep.frequency = FrequencyToHz (Channel->Frequency ()); +#if VDRVERSNUM < 10714 + m_fep.inversion = fe_spectral_inversion_t (Channel->Inversion ()); + m_fep.u.qam.fec_inner = fe_code_rate_t (Channel->CoderateH ()); + m_fep.u.qam.modulation = fe_modulation_t (Channel->Modulation ()); +#else + m_fep.inversion = fe_spectral_inversion_t (dtp.Inversion ()); + m_fep.u.qam.fec_inner = fe_code_rate_t (dtp.CoderateH ()); + m_fep.u.qam.modulation = fe_modulation_t (dtp.Modulation ()); +#endif + m_fep.u.qam.symbol_rate = Channel->Srate () * 1000UL; + } + break; + case FE_OFDM:{ // DVB-T + + // Frequency and OFDM paramaters: + m_fep.frequency = FrequencyToHz (Channel->Frequency ()); +#if VDRVERSNUM < 10714 + m_fep.inversion = fe_spectral_inversion_t (Channel->Inversion ()); + m_fep.u.ofdm.bandwidth = fe_bandwidth_t (Channel->Bandwidth ()); + m_fep.u.ofdm.code_rate_HP = fe_code_rate_t (Channel->CoderateH ()); + m_fep.u.ofdm.code_rate_LP = fe_code_rate_t (Channel->CoderateL ()); + m_fep.u.ofdm.constellation = fe_modulation_t (Channel->Modulation ()); + m_fep.u.ofdm.transmission_mode = fe_transmit_mode_t (Channel->Transmission ()); + m_fep.u.ofdm.guard_interval = fe_guard_interval_t (Channel->Guard ()); + m_fep.u.ofdm.hierarchy_information = fe_hierarchy_t (Channel->Hierarchy ()); +#else + m_fep.inversion = fe_spectral_inversion_t (dtp.Inversion ()); + m_fep.u.ofdm.bandwidth = fe_bandwidth_t (dtp.Bandwidth ()); + m_fep.u.ofdm.code_rate_HP = fe_code_rate_t (dtp.CoderateH ()); + m_fep.u.ofdm.code_rate_LP = fe_code_rate_t (dtp.CoderateL ()); + m_fep.u.ofdm.constellation = fe_modulation_t (dtp.Modulation ()); + m_fep.u.ofdm.transmission_mode = fe_transmit_mode_t (dtp.Transmission ()); + m_fep.u.ofdm.guard_interval = fe_guard_interval_t (dtp.Guard ()); + m_fep.u.ofdm.hierarchy_information = fe_hierarchy_t (dtp.Hierarchy ()); +#endif + } + break; + default: + esyslog ("ERROR: attempt to set channel with unknown DVB frontend type"); + return false; + } + + recv_tune (m_r, (fe_type_t)m_fetype, m_pos, &m_sec, &m_fep, m_pids); + m_tuned = true; + if((m_pids[0].pid==-1)) { + dvb_pid_t pi; + memset(&pi, 0, sizeof(dvb_pid_t)); + recv_pid_add (m_r, &pi); +// printf("add dummy pid 0 @ %p\n", this); + } +#ifdef DEBUG_PIDS + printf ("%p SetChannelDevice: Pidsnum:%d m_pidsnum:%d\n", m_r, m_mcpidsnum, m_pidsnum); + for (int i = 0; i < m_mcpidsnum; i++) { + printf ("Pid:%d\n", m_pids[i].pid); + } +#endif + m_ten.lastseen=m_last=time(NULL); + m_showtuning = true; + return true; +} + +bool cMcliDevice::HasLock (int TimeoutMs) +{ +// printf ("HasLock TimeoutMs:%d\n", TimeoutMs); + + if ((m_ten.s.st & FE_HAS_LOCK) || !TimeoutMs) { + return m_ten.s.st & FE_HAS_LOCK; + } + cMutexLock MutexLock (&mutex); + if (TimeoutMs && !(m_ten.s.st & FE_HAS_LOCK)) { + m_locked.TimedWait (mutex, TimeoutMs); + } + if (m_ten.s.st & FE_HAS_LOCK) { + return true; + } + return false; +} + +bool cMcliDevice::SetPid (cPidHandle * Handle, int Type, bool On) +{ +#ifdef DEBUG_TUNE + printf ("SetPid %d Pid:%d (%s), Type:%d, On:%d, used:%d sid:%d ca_enable:%d channel_ca:%d\n", CardIndex () + 1, Handle->pid, m_chan.Name(), Type, On, Handle->used, m_chan.Sid(), GetCaEnable(), m_chan.Ca (0)); +#endif + dvb_pid_t pi; + memset (&pi, 0, sizeof (dvb_pid_t)); + if (!m_enable) { + return false; + } + LOCK_THREAD; + if (Handle->pid && (On || !Handle->used)) { + m_pidsnum += On ? 1 : -1; + if (m_pidsnum < 0) { + m_pidsnum = 0; + } + + if (On) { + pi.pid = Handle->pid; + if (GetCaEnable() && m_chan.Ca (0)) { + pi.id= m_chan.Sid(); + if(m_chan.Ca(0)<=0xff) { + pi.priority=m_chan.Ca(0)&0x03; + } + } +#ifdef ENABLE_DEVICE_PRIORITY + int Prio = Priority(); + if(Prio>50) // Recording prio high + pi.priority |= 3<<2; + else if(Prio > 10) // Recording prio normal + pi.priority |= 2<<2; + else if(Prio >= 0) // Recording prio low + pi.priority |= 1<<2; + else if(Prio == -1) // Live + pi.priority |= 1<<2; +#endif +// printf ("Add Pid:%d Sid:%d Type:%d Prio:%d %d\n", pi.pid, pi.id, Type, pi.priority, m_chan.Ca(0)); + recv_pid_add (m_r, &pi); + } else { +// printf ("Del Pid:%d\n", Handle->pid); + recv_pid_del (m_r, Handle->pid); + } + } + m_mcpidsnum = recv_pids_get (m_r, m_pids); +#ifdef DEBUG_PIDS + printf ("%p SetPid: Pidsnum:%d m_pidsnum:%d m_filternum:%d\n", m_r, m_mcpidsnum, m_pidsnum, m_filternum); + for (int i = 0; i < m_mcpidsnum; i++) { + printf ("Pid:%d\n", m_pids[i].pid); + } +#endif + m_last=time(NULL); + return true; +} + +bool cMcliDevice::OpenDvr (void) +{ +// printf ("OpenDvr\n"); + m_dvr_open = true; + return true; +} + +void cMcliDevice::CloseDvr (void) +{ +// printf ("CloseDvr\n"); + m_dvr_open = false; +} + +#ifdef GET_TS_PACKETS +int cMcliDevice::GetTSPackets (uchar * Data, int count) +{ + if (!m_enable || !m_dvr_open) { + return 0; + } + m_PB->GetEnd (); + + int size; + uchar *buf = m_PB->GetStartMultiple (count, &size, 0, 0); + if (buf) { + memcpy (Data, buf, size); + m_PB->GetEnd (); + return size; + } else { + return 0; + } +} // cMcliDevice::GetTSPackets +#endif + +bool cMcliDevice::GetTSPacket (uchar * &Data) +{ +#ifdef USE_VDR_PACKET_BUFFER + if (!m_enable || !m_dvr_open) return false; + Data = NULL; + int Count = 0; + if(delivered) { + m_PB->Del(TS_SIZE); + delivered=false; + } + uchar *p = m_PB->Get(Count); + if (p && Count >= TS_SIZE) { + if (*p != TS_SYNC_BYTE) { + for (int i = 1; i < Count; i++) { + if (p[i] == TS_SYNC_BYTE) { + Count = i; + break; + } + } + m_PB->Del(Count); + esyslog("cMcliDevice::GetTSPacket: skipped %d bytes to sync on TS packet on device %d", Count, CardIndex()); + return true; + } + delivered = true; + Data = p; + } + return true; +#else + if (m_enable && m_dvr_open) { + m_PB->GetEnd (); + + int size; + Data = m_PB->GetStart (&size, 0, 0); + } + return true; +#endif +} + +int cMcliDevice::OpenFilter (u_short Pid, u_char Tid, u_char Mask) +{ + if (!m_enable) { + return -1; + } + LOCK_THREAD; + m_filternum++; +// printf ("OpenFilter (%d/%d/%d) pid:%d tid:%d mask:%04x %s\n", m_filternum, m_pidsnum, m_mcpidsnum, Pid, Tid, Mask, ((m_filternum+m_pidsnum) < m_mcpidsnum) ? "PROBLEM!!!":""); + dvb_pid_t pi; + memset (&pi, 0, sizeof (dvb_pid_t)); + pi.pid = Pid; +// printf ("Add Pid:%d\n", pi.pid); + recv_pid_add (m_r, &pi); + m_mcpidsnum = recv_pids_get (m_r, m_pids); +#ifdef DEBUG_PIDS + printf ("%p OpenFilter: Pidsnum:%d m_pidsnum:%d\n", m_r, m_mcpidsnum, m_pidsnum); + for (int i = 0; i < m_mcpidsnum; i++) { + printf ("Pid:%d\n", m_pids[i].pid); + } +#endif + return m_filters->OpenFilter (Pid, Tid, Mask); +} + +void cMcliDevice::CloseFilter (int Handle) +{ + if (!m_enable) { + return; + } + + LOCK_THREAD; + int pid = m_filters->CloseFilter (Handle); + + if ( pid != -1) { +// printf("CloseFilter FULL\n"); + recv_pid_del (m_r, pid); + m_mcpidsnum = recv_pids_get (m_r, m_pids); + } + m_filternum--; +// printf ("CloseFilter(%d/%d/%d) pid:%d %s\n", m_filternum, m_pidsnum, m_mcpidsnum, pid, pid==-1?"PID STILL USED":""); +} + +#ifdef DEVICE_ATTRIBUTES +/* Attribute classes for dvbdevice + main main attributes + .name (String) "DVB", "IPTV", ... + + fe : frontend attributes (-> get from tuner) + .type (int) FE_QPSK, ... + .name (string) Tuner name + .status,.snr,... (int) +*/ +int cMcliDevice::GetAttribute (const char *attr_name, uint64_t * val) +{ + int ret = 0; + uint64_t rval = 0; + + if (!strcmp (attr_name, "fe.status")) { + rval = m_ten.s.st; + if ((m_ten.lastseen+LASTSEEN_TIMEOUT)>time(0)) { + rval|= (m_ten.rotor_status&3)<<8; + rval|= (1+m_ten.slot)<<12; + } + } else if (!strcmp (attr_name, "fe.signal")) { + rval = m_ten.s.strength; + } else if (!strcmp (attr_name, "fe.snr")) { + rval = m_ten.s.snr; + } else if (!strcmp (attr_name, "fe.ber")) { + rval = m_ten.s.ber; + } else if (!strcmp (attr_name, "fe.unc")) { + rval = m_ten.s.ucblocks; + } else if (!strcmp (attr_name, "fe.type")) { + rval = m_fetype; + } else if (!strcmp (attr_name, "is.mcli")) { + rval = 1; + } else if (!strcmp (attr_name, "fe.lastseen")) { + rval = m_ten.lastseen; + } else + ret = -1; + + if (val) + *val = rval; + return ret; +} + +int cMcliDevice::GetAttribute (const char *attr_name, char *val, int maxret) +{ + int ret = 0; + if (!strcmp (attr_name, "fe.uuid")) { + strncpy (val, "NetCeiver", maxret); + val[maxret - 1] = 0; + } else if (!strcmp (attr_name, "fe.name")) { + strncpy (val, "NetCeiver", maxret); + val[maxret - 1] = 0; + } else if (!strncmp (attr_name, "main.", 5)) { + if (!strncmp (attr_name + 5, "name", 4)) { + if (val && maxret > 0) { + strncpy (val, "NetCeiver", maxret); + val[maxret - 1] = 0; + } + return 0; + } + } else { + ret = -1; + } + return ret; +} +#endif |