Merge branch 'internal'

This commit is contained in:
Ralph Metzler 2019-08-05 16:06:26 +02:00
commit 0cc91fbe5f
36 changed files with 1581 additions and 115 deletions

View File

@ -14,6 +14,9 @@ libdddvb:
libdddvb-install:
$(MAKE) -C lib install
libdddvb-clean:
$(MAKE) -C lib clean
dep:
DIR=`pwd`; (cd $(TOPDIR); make SUBDIRS=$$DIR dep)

View File

@ -27,6 +27,7 @@ uint8_t fill[188]={0x47, 0x1f, 0xff, 0x10,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff };
#if 0
uint8_t ts[188]={0x47, 0x0a, 0xaa, 0x00,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
@ -40,6 +41,21 @@ uint8_t ts[188]={0x47, 0x0a, 0xaa, 0x00,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff };
#else
uint8_t ts[188]={0x47, 0x0a, 0xaa, 0x00,
0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,
0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,
0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,
0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,
0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,
0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,
0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,
0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,
0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,
0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,
0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,
0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa };
#endif
void proc_buf(uint8_t *buf, uint32_t *d)
{

View File

@ -238,7 +238,7 @@ int main(int argc, char **argv)
printf("Octopus MAXM4\n");
break;
case 0x0011:
fname="CIBridgeV1B_CIBridgeV1B.fpga";
fname="DVBBridgeV2B_DD01_0011.fpga";
printf("Octopus CI\n");
break;
case 0x0012:
@ -250,7 +250,7 @@ int main(int argc, char **argv)
printf("Octopus PRO\n");
break;
case 0x0020:
fname="DVBBridgeV2B_DD01_0020.fpga";
fname="DVBBridgeV2C_DD01_0020.fpga";
printf("Octopus GT Mini\n");
break;
case 0x0201:
@ -273,6 +273,10 @@ int main(int argc, char **argv)
fname="SDRModulatorV1A_DD01_0221_IQ.fpga";
printf("SDRModulator IQ\n");
break;
case 0x0222:
fname="SDRModulatorV1A_DD01_0222_DVBT.fpga";
printf("SDRModulator DVBT\n");
break;
default:
printf("UNKNOWN\n");
break;
@ -285,7 +289,7 @@ int main(int argc, char **argv)
printf("Using bitstream %s\n", fname);
fsize = lseek(fh,0,SEEK_END);
if( fsize > 4000000 || fsize < SectorSize )
if( fsize > FlashSize/2 - 0x10000 || fsize < SectorSize )
{
close(fh);
printf("Invalid File Size \n");

View File

@ -10,6 +10,7 @@
#include <fcntl.h>
#include <sys/ioctl.h>
#include <pthread.h>
#include <getopt.h>
#include <linux/dvb/mod.h>
@ -51,33 +52,96 @@ static int get_property(int fd, uint32_t cmd, uint32_t *data)
int main()
int main(int argc, char*argv[])
{
int fd;
struct dvb_mod_params mp;
struct dvb_mod_channel_params mc;
uint32_t data;
int adapter = 0, channel = 0, gain = -1;
int32_t base = -1, freq = -1, rate = -1;
char mod_name[128];
fd = open("/dev/dvb/adapter0/mod0", O_RDONLY);
while (1) {
int cur_optind = optind ? optind : 1;
int option_index = 0;
int c;
static struct option long_options[] = {
{"adapter", required_argument, 0, 'a'},
{"channel", required_argument, 0, 'c'},
{"gain", required_argument, 0, 'g'},
{"base", required_argument, 0, 'b'},
{"frequency", required_argument, 0, 'f'},
{"rate", required_argument, 0, 'r'},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv,
"a:c:g:b:f:r:",
long_options, &option_index);
if (c==-1)
break;
switch (c) {
case 'a':
adapter = strtoul(optarg, NULL, 0);
break;
case 'c':
channel = strtoul(optarg, NULL, 0);
break;
case 'g':
gain = strtoul(optarg, NULL, 0);
break;
case 'b':
base = strtoul(optarg, NULL, 0);
break;
case 'f':
freq = strtoul(optarg, NULL, 0);
break;
case 'r':
if (!strcmp(optarg, "DVBT_8"))
rate = SYS_DVBT_8;
else if (!strcmp(optarg, "DVBT_7"))
rate = SYS_DVBT_7;
else if (!strcmp(optarg, "DVBT_6"))
rate = SYS_DVBT_6;
else if (!strcmp(optarg, "ISDBT_6"))
rate = SYS_ISDBT_6;
else rate = strtoul(optarg, NULL, 0);
break;
default:
break;
}
}
if (optind < argc) {
printf("too man arguments\n");
exit(1);
}
snprintf(mod_name, 127, "/dev/dvb/adapter%d/mod%d", adapter, channel);
fd = open(mod_name, O_RDONLY);
if (fd < 0) {
printf("Could not open modulator device.\n");
exit(1);
}
/* gain 0-255 */
get_property(fd, MODULATOR_GAIN, &data);
printf("Modulator gain = %u\n", data);
set_property(fd, MODULATOR_GAIN, 100);
//get_property(fd, MODULATOR_GAIN, &data);
//printf("Modulator gain = %u\n", data);
//set_property(fd, MODULATOR_GAIN, 100);
get_property(fd, MODULATOR_GAIN, &data);
printf("Modulator gain = %u\n", data);
//get_property(fd, MODULATOR_ATTENUATOR, &data);
//printf("Modulator attenuator = %u\n", data);
get_property(fd, MODULATOR_ATTENUATOR, &data);
printf("Modulator attenuator = %u\n", data);
get_property(fd, MODULATOR_STATUS, &data);
printf("Modulator status = %u\n", data);
set_property(fd, MODULATOR_STATUS, 2);
if (base > 0)
set_property(fd, MODULATOR_BASE_FREQUENCY, base);
if (freq > 0)
set_property(fd, MODULATOR_FREQUENCY, base);
if (rate > 0)
set_property(fd, MODULATOR_OUTPUT_RATE, rate);
//set_property(fd, MODULATOR_RESET, 0);
close(fd);
}

View File

@ -1,7 +1,7 @@
/*
* ddbridge-ci.c: Digital Devices bridge and DuoFlex CI driver
*
* Copyright (C) 2010-2017 Digital Devices GmbH
* Copyright (C) 2010-2019 Digital Devices GmbH
* Ralph Metzler <rjkm@metzlerbros.de>
* Marcus Metzler <mocm@metzlerbros.de>
*

View File

@ -1,7 +1,7 @@
/*
* ddbridge-core.c: Digital Devices bridge core functions
*
* Copyright (C) 2010-2016 Digital Devices GmbH
* Copyright (C) 2010-2019 Digital Devices GmbH
* Marcus Metzler <mocm@metzlerbros.de>
* Ralph Metzler <rjkm@metzlerbros.de>
*
@ -1105,7 +1105,7 @@ static void dummy_release(struct dvb_frontend *fe)
}
static struct dvb_frontend_ops dummy_ops = {
.delsys = { SYS_DVBC_ANNEX_A },
.delsys = { SYS_DVBC_ANNEX_A, SYS_DVBS, SYS_DVBS2 },
.info = {
.name = "DUMMY DVB-C/C2 DVB-T/T2",
.frequency_stepsize = 166667, /* DVB-T only */
@ -1399,7 +1399,7 @@ static struct stv0910_cfg stv0910_p = {
.parallel = 1,
.rptlvl = 4,
.clk = 30000000,
.tsspeed = 0x10,
.tsspeed = 0x20,
};
static int has_lnbh25(struct i2c_adapter *i2c, u8 adr)
@ -1524,6 +1524,7 @@ static void dvb_input_detach(struct ddb_input *input)
case 0x41:
if (dvb->fe2)
dvb_unregister_frontend(dvb->fe2);
/* fallthrough */
case 0x40:
if (dvb->fe)
dvb_unregister_frontend(dvb->fe);
@ -1843,8 +1844,8 @@ static int dvb_input_attach(struct ddb_input *input)
memcpy(&dvb->fe2->ops.tuner_ops,
&dvb->fe->ops.tuner_ops,
sizeof(struct dvb_tuner_ops));
dvb->attached = 0x41;
}
dvb->attached = 0x41;
return 0;
}
@ -2071,7 +2072,8 @@ static void ddb_port_probe(struct ddb_port *port)
/* Handle missing ports and ports without I2C */
if (dummy_tuner && !port->nr &&
link->ids.device == 0x0005) {
(link->ids.device == 0x0005 ||
link->ids.device == 0x000a)) {
port->name = "DUMMY";
port->class = DDB_PORT_TUNER;
port->type = DDB_TUNER_DUMMY;
@ -2561,7 +2563,7 @@ static void ddb_dma_init(struct ddb_io *io, int nr, int out, int irq_nr)
dma->regs = rm->odma->base + rm->odma->size * nr;
dma->bufregs = rm->odma_buf->base + rm->odma_buf->size * nr;
if (io->port->dev->link[0].info->type == DDB_MOD &&
io->port->dev->link[0].info->version == 3) {
io->port->dev->link[0].info->version >= 16) {
dma->num = OUTPUT_DMA_BUFS_SDR;
dma->size = OUTPUT_DMA_SIZE_SDR;
dma->div = 1;
@ -3496,7 +3498,7 @@ static long ddb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (copy_from_user(&i2c, parg, sizeof(i2c)))
return -EFAULT;
if (i2c.bus > dev->link[0].info->regmap->i2c->num)
if (i2c.bus > dev->i2c_num)
return -EINVAL;
if (i2c.mlen + i2c.hlen > 512)
return -EINVAL;
@ -3520,7 +3522,7 @@ static long ddb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (copy_from_user(&i2c, parg, sizeof(i2c)))
return -EFAULT;
if (i2c.bus > dev->link[0].info->regmap->i2c->num)
if (i2c.bus > dev->i2c_num)
return -EINVAL;
if (i2c.mlen + i2c.hlen > 250)
return -EINVAL;
@ -3876,6 +3878,24 @@ static ssize_t bpsnr_show(struct device *device,
return sprintf(buf, "%s\n", snr);
}
static ssize_t gtl_snr_show(struct device *device,
struct device_attribute *attr, char *buf)
{
struct ddb *dev = dev_get_drvdata(device);
int num = attr->attr.name[6] - 0x30;
char snr[16];
ddbridge_flashread(dev, num, snr, 0x10, 15);
snr[15] = 0; /* in case it is not terminated on EEPROM */
return sprintf(buf, "%s\n", snr);
}
static ssize_t gtl_snr_store(struct device *device, struct device_attribute *attr,
const char *buf, size_t count)
{
return 0;
}
static ssize_t redirect_show(struct device *device,
struct device_attribute *attr, char *buf)
{
@ -4121,6 +4141,12 @@ static struct device_attribute ddb_attrs_snr[] = {
__ATTR(snr3, 0664, snr_show, snr_store),
};
static struct device_attribute ddb_attrs_gtl_snr[] = {
__ATTR(gtlsnr1, 0664, gtl_snr_show, gtl_snr_store),
__ATTR(gtlsnr2, 0664, gtl_snr_show, gtl_snr_store),
__ATTR(gtlsnr3, 0664, gtl_snr_show, gtl_snr_store),
};
static struct device_attribute ddb_attrs_ctemp[] = {
__ATTR_MRO(temp0, ctemp_show),
__ATTR_MRO(temp1, ctemp_show),
@ -4191,6 +4217,9 @@ static void ddb_device_attrs_del(struct ddb *dev)
device_remove_file(dev->ddb_dev, &ddb_attrs_snr[i]);
device_remove_file(dev->ddb_dev, &ddb_attrs_ctemp[i]);
}
if (dev->link[0].info->regmap->gtl)
for (i = 0; i < dev->link[0].info->regmap->gtl->num; i++)
device_remove_file(dev->ddb_dev, &ddb_attrs_gtl_snr[i]);
for (i = 0; ddb_attrs[i].attr.name; i++)
device_remove_file(dev->ddb_dev, &ddb_attrs[i]);
}
@ -4223,6 +4252,10 @@ static int ddb_device_attrs_add(struct ddb *dev)
&ddb_attrs_led[i]))
goto fail;
}
if (dev->link[0].info->regmap->gtl)
for (i = 0; i < dev->link[0].info->regmap->gtl->num; i++)
if (device_create_file(dev->ddb_dev, &ddb_attrs_gtl_snr[i]))
goto fail;
for (i = 0; i < 4; i++)
if (dev->link[i].info &&
dev->link[i].info->tempmon_irq)
@ -4439,7 +4472,7 @@ static void tempmon_setfan(struct ddb_link *link)
while (pwm < 10 && temp >= link->temp_tab[pwm + 1])
pwm += 1;
} else {
while (pwm > 1 && temp < link->temp_tab[pwm - 2])
while (pwm > 1 && temp < (link->temp_tab[pwm] - 2))
pwm -= 1;
}
ddblwritel(link, (pwm << 8), TEMPMON_FANCONTROL);

View File

@ -1,7 +1,7 @@
/*
* ddbridge-hw.c: Digital Devices device information tables
*
* Copyright (C) 2010-2017 Digital Devices GmbH
* Copyright (C) 2010-2019 Digital Devices GmbH
* Ralph Metzler <rjkm@metzlerbros.de>
* Marcus Metzler <mocm@metzlerbros.de>
*
@ -537,6 +537,16 @@ static const struct ddb_info ddb_sdr_iq = {
.tempmon_irq = 8,
};
static const struct ddb_info ddb_sdr_dvbt = {
.type = DDB_MOD,
.name = "Digital Devices DVBT",
.version = 18,
.regmap = &octopus_sdr_map,
.port_num = 16,
.temp_num = 1,
.tempmon_irq = 8,
};
static const struct ddb_info ddb_octopro_hdin = {
.type = DDB_OCTOPRO_HDIN,
.name = "Digital Devices OctopusNet Pro HDIN",
@ -789,7 +799,7 @@ static const struct ddb_device_id ddb_device_ids[] = {
DDB_DEVID(0x0210, 0x0003, ddb_mod_fsm_8),
DDB_DEVID(0x0220, 0x0001, ddb_sdr_atv),
DDB_DEVID(0x0221, 0x0001, ddb_sdr_iq),
DDB_DEVID(0x0222, 0x0001, ddb_sdr_iq),
DDB_DEVID(0x0222, 0x0001, ddb_sdr_dvbt),
/* testing on OctopusNet Pro */
DDB_DEVID(0x0320, 0xffff, ddb_octopro_hdin),

View File

@ -1,7 +1,7 @@
/*
* ddbridge-i2c.c: Digital Devices bridge i2c driver
*
* Copyright (C) 2010-2017 Digital Devices GmbH
* Copyright (C) 2010-2019 Digital Devices GmbH
* Ralph Metzler <rjkm@metzlerbros.de>
* Marcus Metzler <mocm@metzlerbros.de>
*
@ -65,7 +65,7 @@ static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd)
}
val &= 0x70000;
if (val == 0x20000)
dev_err(dev->dev, "I2C bus errorx\n");
dev_err(dev->dev, "I2C bus error\n");
if (val)
return -EIO;
return 0;

View File

@ -1,7 +1,7 @@
/*
* ddbridge-i2c.h: Digital Devices bridge i2c driver
*
* Copyright (C) 2010-2017 Digital Devices GmbH
* Copyright (C) 2010-2019 Digital Devices GmbH
* Marcus Metzler <mocm@metzlerbros.de>
* Ralph Metzler <rjkm@metzlerbros.de>
*

View File

@ -83,7 +83,17 @@ static int ddb_mci_cmd_raw_unlocked(struct mci *state,
stat = wait_for_completion_timeout(&state->base->completion, HZ);
if (stat == 0) {
u32 istat = ddblreadl(link, INTERRUPT_STATUS);
printk("MCI timeout\n");
val = ddblreadl(link, MCI_CONTROL);
if (val == 0xffffffff)
printk("Lost PCIe link!\n");
else {
printk("DDBridge IRS %08x\n", istat);
if (istat & 1)
ddblwritel(link, istat & 1, INTERRUPT_ACK);
}
return -EIO;
}
if (res && res_len)

View File

@ -114,7 +114,7 @@
#define MCI_CMD_STOP (0x01)
#define MCI_CMD_GETSTATUS (0x02)
#define MCI_CMD_GETSIGNALINFO (0x03)
#define MCI_CMD_RFPOWER (0x04)
//#define MCI_CMD_RFPOWER (0x04)
#define MCI_CMD_SEARCH_DVBS (0x10)
#define MCI_CMD_SEARCH_ISDBS (0x11)
@ -147,7 +147,8 @@
#define M4_CMD_GET_L1INFO (0x50)
#define M4_CMD_GET_IDS (0x51)
#define M4_CMD_GET_DVBT_TPS (0x52)
#define M4_CMD_GET_BBHEADER (0x53)
#define MCI_CMD_GET_BBHEADER (0x53)
#define M4_CMD_GET_BBHEADER (MCI_CMD_GET_BBHEADER)
#define M4_CMD_GET_ISDBT_TMCC (0x54)
#define M4_CMD_GET_ISDBS_TMCC (0x55)
#define M4_CMD_GET_ISDBC_TSMF (0x56)
@ -179,6 +180,12 @@
#define M4_SIGNALINFO_FLAG_CHANGE (0x01)
#define M4_SIGNALINFO_FLAG_EWS (0x02)
#define SX8_ROLLOFF_25 1
#define SX8_ROLLOFF_20 2
#define SX8_ROLLOFF_15 5
#define SX8_ROLLOFF_10 3
#define SX8_ROLLOFF_05 4
#define MCI_SUCCESS(status) ((status & MCI_STATUS_UNSUPPORTED) == 0)
@ -286,27 +293,38 @@ struct mci_command {
u8 retry;
u32 frequency;
} j83b_search;
struct {
u8 flags; // Bit 0 : 1 = short info (1st 4 Bytes)
} get_signalinfo;
struct {
u8 tap;
u8 rsvd;
u16 point;
} get_iq_symbol;
struct {
u8 flags; /* Bit 0 : 0 = VTM, 1 = SCAN. Bit 1: Set Gain */
u8 roll_off;
u8 rsvd1;
u8 rsvd2;
u32 frequency;
u32 symbol_rate; /* Only in VTM mode. */
u16 gain;
uint8_t flags; /* Bit 0 : 0 = VTM/SDR, 1 = SCAN, Bit 1: Disable AGC, Bit 2: Set Gain */
uint8_t roll_off;
uint8_t rsvd1;
uint8_t rsvd2;
uint32_t frequency;
uint32_t symbol_rate; /* Only in VTM/SDR mode, SCAN Mode uses exactly 1550/24 MSymbols/s.*/
uint8_t gain; /* Gain in 0.25 dB Steps */
/* Frequency, symbolrate and gain can be schanged while running */
} sx8_start_iq;
struct {
/* Bit 1:0 = STVVGLNA Gain. 0 = AGC, 1 = 0dB,
2 = Minimum, 3 = Maximum */
u8 flags;
uint8_t flags;
/* Bit 0:1 Preamp Mode; 0 = Preamp AGC, 1 == Minimum (~ -17dB) ,
2 = Medium, 3 = Maximum gain {~ 15dB}
Bit 2: Bypass Input LNA (6 dB less gain) (Note this is after Preamp)
Bit 4: Set RF Gain
Bit 5: Freeze RF Gain (Turn AGC off at current gain, only when already enabled)
Bit 7: Optimize RF Gain and freeze for FFT */
uint8_t rf_gain; /* 0 .. 50 dB */
} sx8_input_enable;
struct {
@ -357,8 +375,8 @@ struct mci_result {
struct {
u8 standard; /* 1 = DVB-S, 2 = DVB-S2X */
u8 pls_code; /* puncture rate for DVB-S */
u8 roll_off; /* 2-0: rolloff */
u8 pls_code; /* PLS code for DVB-S2/S2X, puncture rate for DVB-S */
u8 roll_off; /* 2-0: rolloff, 7: spectrum inversion */
u8 flags;
u32 frequency; /* actual frequency in Hz */
u32 symbol_rate; /* actual symbolrate in Hz */
@ -391,8 +409,6 @@ struct mci_result {
u8 modulation2; // bit 7..5: CodeRate Low, bit 4..3 Guard Interval, bit 2..1 FFT Mode
u8 Rsvd0;
u8 Flags;
//u16 tps_cell_id; /* Cell Identifier */
u32 frequency; /* actual frequency in Hz */
u32 rsvd1;
s16 channel_power; /* channel power in dBm x 100 */
@ -492,6 +508,7 @@ struct mci_result {
struct {
u8 TPSInfo[7];
// uint16_t TPS_CellID; // Cell Identifier
} DVBT_TPSInfo;
struct {
@ -620,6 +637,8 @@ struct mci_result {
u8 SYNCD[2];
u8 rsvd;
u8 ISSY[3];
u8 min_input_stream_id;
u8 max_input_stream_id;
} BBHeader;
struct {
@ -644,7 +663,11 @@ struct mci_result {
u8 Extension[8]; // 61 bits, right aligned
} ISDBS_TMCCInfo;
};
u32 version[4];
u32 version[3];
u32 version_rsvd;
u8 version_major;
u8 version_minor;
u8 version_sub;
};

View File

@ -1477,12 +1477,46 @@ static int mod3_set_ari(struct ddb_mod *mod, u32 rate)
}
static int mod3_set_sample_rate(struct ddb_mod *mod, u32 rate)
{
u32 cic, inc;
switch (rate) {
case SYS_DVBT_6:
inc = 1917396114;
cic = 8;
break;
case SYS_DVBT_7:
inc = 1957341867;
cic = 7;
break;
case SYS_DVBT_8:
//rate = 8126984;
inc = 1917396114;
cic = 6;
break;
case SYS_ISDBT_6:
inc = 1988410754;
cic = 7;
break;
default:
return -EINVAL;
}
ddbwritel(mod->port->dev, inc, SDR_CHANNEL_ARICW(mod->port->nr));
ddbwritel(mod->port->dev, cic << 8, SDR_CHANNEL_CONFIG(mod->port->nr));
return 0;
}
static int mod3_prop_proc(struct ddb_mod *mod, struct dtv_property *tvp)
{
switch (tvp->cmd) {
case MODULATOR_OUTPUT_ARI:
return mod3_set_ari(mod, tvp->u.data);
case MODULATOR_OUTPUT_RATE:
return mod3_set_sample_rate(mod, tvp->u.data);
case MODULATOR_FREQUENCY:
return mod3_set_frequency(mod, tvp->u.data);
@ -1542,15 +1576,37 @@ static int mod_prop_proc(struct ddb_mod *mod, struct dtv_property *tvp)
return 0;
}
static int mod_prop_get3(struct ddb_mod *mod, struct dtv_property *tvp)
{
struct ddb *dev = mod->port->dev;
switch (tvp->cmd) {
case MODULATOR_INFO:
tvp->u.data = dev->link[0].info->version;
return 0;
case MODULATOR_GAIN:
tvp->u.data = 0xff & ddbreadl(dev, RF_VGA);
return 0;
default:
return -1;
}
}
static int mod_prop_get(struct ddb_mod *mod, struct dtv_property *tvp)
{
struct ddb *dev = mod->port->dev;
if (mod->port->dev->link[0].info->version >= 16)
return mod_prop_get3(mod, tvp);
if (mod->port->dev->link[0].info->version != 2)
return -1;
switch (tvp->cmd) {
case MODULATOR_INFO:
tvp->u.data = 2;
return 0;
case MODULATOR_GAIN:
tvp->u.data = 0xff & ddbreadl(dev, RF_VGA);;
tvp->u.data = 0xff & ddbreadl(dev, RF_VGA);
return 0;
case MODULATOR_ATTENUATOR:
@ -1897,6 +1953,8 @@ int ddbridge_mod_init(struct ddb *dev)
return mod_init_3(dev, 503250000);
case 17:
return mod_init_sdr_iq(dev);
case 18:
return mod_init_sdr_iq(dev);
default:
return -1;
}

View File

@ -44,7 +44,7 @@ static u16 calc_pcs16(struct dvb_ns_params *p, int ipv)
u32 sum = 0, i;
u16 pcs;
for (i = 0; i < ipv ? 16 : 4; i += 2) {
for (i = 0; i < (ipv ? 16 : 4); i += 2) {
sum += (p->sip[i] << 8) | p->sip[i + 1];
sum += (p->dip[i] << 8) | p->dip[i + 1];
}

View File

@ -26,8 +26,14 @@
#include "ddbridge-i2c.h"
#include "ddbridge-mci.h"
static int default_mod = 3;
module_param(default_mod, int, 0444);
MODULE_PARM_DESC(default_mod, "default modulations enabled, default is 3 (1 = QPSK, 2 = 8PSK, 4 = 16APSK, ...)");
static const u32 MCLK = (1550000000 / 12);
static const u32 MAX_LDPC_BITRATE = (720000000);
/* Add 2MBit/s overhead allowance (minimum factor is 90/32400 for QPSK w/o Pilots) */
static const u32 MAX_LDPC_BITRATE = (720000000 + 2000000);
static const u32 MAX_DEMOD_LDPC_BITRATE = (1550000000 / 6);
#define SX8_TUNER_NUM 4
@ -52,6 +58,7 @@ struct sx8 {
int first_time_lock;
int started;
int iq_started;
u32 bb_mode;
u32 local_frequency;
@ -131,6 +138,7 @@ static int read_status(struct dvb_frontend *fe, enum fe_status *status)
dvbs2_bits_per_symbol[
state->mci.signal_info.
dvbs2_signal_info.pls_code];
//printk("PLS %02x\n", state->mci.signal_info.dvbs2_signal_info.pls_code);
} else
sx8_base->used_ldpc_bitrate[state->mci.nr] = 0;
}
@ -151,6 +159,25 @@ static int mci_set_tuner(struct dvb_frontend *fe, u32 tuner, u32 on)
return ddb_mci_cmd(&state->mci, &cmd, NULL);
}
static int stop_iq(struct dvb_frontend *fe)
{
struct sx8 *state = fe->demodulator_priv;
struct mci_base *mci_base = state->mci.base;
struct sx8_base *sx8_base = (struct sx8_base *) mci_base;
struct mci_command cmd;
u32 input = state->mci.tuner;
if (!state->iq_started)
return -1;
memset(&cmd, 0, sizeof(cmd));
cmd.command = SX8_CMD_STOP_IQ;
cmd.demod = state->mci.demod;
ddb_mci_cmd(&state->mci, &cmd, NULL);
ddb_mci_config(&state->mci, SX8_TSCONFIG_MODE_NORMAL);
state->iq_started = 0;
return 0;
}
static int stop(struct dvb_frontend *fe)
{
struct sx8 *state = fe->demodulator_priv;
@ -285,13 +312,13 @@ unlock:
if (sx8_base->iq_mode) {
cmd.command = SX8_CMD_ENABLE_IQOUTPUT;
cmd.demod = state->mci.demod;
cmd.output = 0;
cmd.output = p->stream_id & 7;
ddb_mci_cmd(&state->mci, &cmd, NULL);
ddb_mci_config(&state->mci, ts_config);
}
if (p->stream_id != NO_STREAM_ID_FILTER && p->stream_id != 0x80000000)
if (p->stream_id != NO_STREAM_ID_FILTER && !(p->stream_id & 0xf0000000))
flags |= 0x80;
printk("frontend %u: tuner=%u demod=%u\n", state->mci.nr, state->mci.tuner, state->mci.demod);
//printk("frontend %u: tuner=%u demod=%u\n", state->mci.nr, state->mci.tuner, state->mci.demod);
cmd.command = MCI_CMD_SEARCH_DVBS;
cmd.dvbs2_search.flags = flags;
cmd.dvbs2_search.s2_modulation_mask = modmask;
@ -357,7 +384,7 @@ unlock:
cmd.demod = state->mci.demod;
stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
if (stat)
stop(fe);
stop_iq(fe);
ddb_mci_config(&state->mci, ts_config);
return stat;
}
@ -369,16 +396,18 @@ static int set_parameters(struct dvb_frontend *fe)
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
u32 ts_config = SX8_TSCONFIG_MODE_NORMAL, iq_mode = 0, isi;
stop(fe);
isi = p->stream_id;
if (isi != NO_STREAM_ID_FILTER) {
iq_mode = (isi & 0x30000000) >> 28;
}
if (iq_mode)
ts_config = (SX8_TSCONFIG_TSHEADER | SX8_TSCONFIG_MODE_IQ);
stop(fe);
if (iq_mode < 2) {
u32 mask;
stop_iq(fe);
switch (p->modulation) {
case APSK_256:
mask = 0x7f;
@ -396,17 +425,22 @@ static int set_parameters(struct dvb_frontend *fe)
mask = 0x07;
break;
default:
mask = 0x03;
mask = default_mod;
break;
}
stat = start(fe, 3, mask, ts_config);
if (!stat) {
state->started = 1;
state->first_time_lock = 1;
state->mci.signal_info.status = MCI_DEMOD_WAIT_SIGNAL;
}
} else {
stat = start_iq(fe, iq_mode & 1, 4, ts_config);
}
if (!stat) {
state->started = 1;
state->first_time_lock = 1;
state->mci.signal_info.status = MCI_DEMOD_WAIT_SIGNAL;
if (!stat) {
state->iq_started = 1;
state->first_time_lock = 1;
state->mci.signal_info.status = MCI_DEMOD_WAIT_SIGNAL;
}
}
return stat;
}
@ -446,6 +480,7 @@ static int set_input(struct dvb_frontend *fe, int input)
return -EINVAL;
if (state->mci.tuner == input)
return 0;
stop_iq(fe);
stop(fe);
state->mci.tuner = p->input = input;
return 0;
@ -453,6 +488,7 @@ static int set_input(struct dvb_frontend *fe, int input)
static int sleep(struct dvb_frontend *fe)
{
stop_iq(fe);
stop(fe);
return 0;
}

View File

@ -1,8 +1,9 @@
/*
* ddbridge.h: Digital Devices PCIe bridge driver
*
* Copyright (C) 2010-2017 Digital Devices GmbH
* Ralph Metzler <rmetzler@digitaldevices.de>
* Copyright (C) 2010-2019 Digital Devices GmbH
* Marcus Metzler <mocm@metzlerbros.de>
* Ralph Metzler <rjkm@metzlerbros.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View File

@ -115,7 +115,7 @@ ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf)
void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf)
{
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
rbuf->pread = &rbuf->pwrite;
rbuf->pread = rbuf->pwrite;
#else
/* dvb_ringbuffer_flush() counts as read operation
* smp_load_acquire() to load write pointer

View File

@ -598,6 +598,7 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
unsigned demux_pad = 0;
unsigned dvr_pad = 0;
unsigned ntuner = 0, ndemod = 0;
u16 source_pad = 0;
int ret;
static const char *connector_name = "Television";
@ -657,8 +658,19 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
ret = media_device_register_entity(mdev, conn);
if (ret)
return ret;
if (!ntuner) {
if (!ntuner)
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,2,0))
if ((ret = media_get_pad_index(tuner, true,
PAD_SIGNAL_ANALOG)) < 0)
return ret;
source_pad = (u16) ret;
ret = 0;
#else
source_pad = TUNER_PAD_RF_INPUT;
#endif
ret = media_create_pad_links(mdev,
MEDIA_ENT_F_CONN_RF,
conn, 0,
@ -666,22 +678,33 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
demod, 0,
MEDIA_LNK_FL_ENABLED,
false);
else
} else {
ret = media_create_pad_links(mdev,
MEDIA_ENT_F_CONN_RF,
conn, 0,
MEDIA_ENT_F_TUNER,
tuner, TUNER_PAD_RF_INPUT,
tuner, source_pad,
MEDIA_LNK_FL_ENABLED,
false);
}
if (ret)
return ret;
}
if (ntuner && ndemod) {
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,2,0))
if ((ret = media_get_pad_index(tuner, true, PAD_SIGNAL_ANALOG)) < 0)
return ret;
source_pad = (u16) ret;
ret = 0;
#else
source_pad = TUNER_PAD_OUTPUT;
#endif
ret = media_create_pad_links(mdev,
MEDIA_ENT_F_TUNER,
tuner, TUNER_PAD_OUTPUT,
tuner, source_pad,
MEDIA_ENT_F_DTV_DEMOD,
demod, 0, MEDIA_LNK_FL_ENABLED,
false);

View File

@ -355,6 +355,7 @@ static int read_tps(struct cxd_state *state, u8 *tps)
/* OFDMInfo[3] [3:0] OFDM_NDSYM[11:8] */
/* OFDMInfo[4] [7:0] OFDM_NDSYM[7:0] */
#if 0
static int read_t2_ofdm_info(struct cxd_state *state, u8 *ofdm)
{
if (state->last_status != 0x1f)
@ -365,6 +366,7 @@ static int read_t2_ofdm_info(struct cxd_state *state, u8 *ofdm)
unfreeze_regst(state);
return 0;
}
#endif
/* Read DVBT2 QAM,
Data PLP
@ -390,6 +392,7 @@ static int read_t2_ofdm_info(struct cxd_state *state, u8 *ofdm)
19-37 same for common PLP
*/
#if 0
static int read_t2_tlp_info(struct cxd_state *state, u8 off, u8 count, u8 *tlp)
{
if (state->last_status != 0x1f)
@ -400,6 +403,7 @@ static int read_t2_tlp_info(struct cxd_state *state, u8 off, u8 count, u8 *tlp)
unfreeze_regst(state);
return 0;
}
#endif
static void Active_to_Sleep(struct cxd_state *state)
{
@ -2243,7 +2247,7 @@ static int get_algo(struct dvb_frontend *fe)
static int get_fe_t2(struct cxd_state *state, struct dtv_frontend_properties *p)
{
struct dvb_frontend *fe = &state->frontend;
//struct dvb_frontend *fe = &state->frontend;
u8 ofdm[5], modcod[2];
freeze_regst(state);
@ -2343,7 +2347,7 @@ static int get_fe_t2(struct cxd_state *state, struct dtv_frontend_properties *p)
static int get_fe_t(struct cxd_state *state, struct dtv_frontend_properties *p)
{
struct dvb_frontend *fe = &state->frontend;
//struct dvb_frontend *fe = &state->frontend;
u8 tps[7];
read_tps(state, tps);
@ -2444,7 +2448,7 @@ static int get_fe_t(struct cxd_state *state, struct dtv_frontend_properties *p)
static int get_fe_c(struct cxd_state *state, struct dtv_frontend_properties *p)
{
struct dvb_frontend *fe = &state->frontend;
//struct dvb_frontend *fe = &state->frontend;
u8 qam;
freeze_regst(state);

View File

@ -106,6 +106,7 @@ static int lnbh25_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
return 0;
}
#if 0
static int lnbh25_set_tone(struct dvb_frontend *fe,
enum fe_sec_tone_mode tone)
{
@ -113,6 +114,7 @@ static int lnbh25_set_tone(struct dvb_frontend *fe,
return 0;
}
#endif
static int lnbh25_init(struct lnbh25 *lnbh)
{

View File

@ -98,26 +98,6 @@ struct mxl {
unsigned long tune_time;
};
static void le32_to_cpusn(u32 *data, u32 size)
{
u32 i;
for (i = 0; i < size; data++, i += 4)
le32_to_cpus(data);
}
static void flip_data_in_dword(u32 size, u8 *d)
{
u32 i;
u8 t;
for (i = 0; i < size; i += 4) {
t = d[i + 3]; d[i + 3] = d[i]; d[i] = t;
t = d[i + 2]; d[i + 2] = d[i + 1]; d[i + 1] = t;
}
}
static void convert_endian(u8 flag, u32 size, u8 *d)
{
u32 i;
@ -249,6 +229,7 @@ static int write_register(struct mxl *state, u32 reg, u32 val)
return stat;
}
#if 0
static int write_register_block(struct mxl *state, u32 reg,
u32 size, u8 *data)
{
@ -272,6 +253,7 @@ static int write_register_block(struct mxl *state, u32 reg,
mutex_unlock(&state->base->i2c_lock);
return stat;
}
#endif
static int write_firmware_block(struct mxl *state,
u32 reg, u32 size, u8 *regDataPtr)
@ -375,6 +357,7 @@ static int update_by_mnemonic(struct mxl *state,
return stat;
}
#if 0
static void extract_from_mnemonic(u32 regAddr, u8 lsbPos, u8 width,
u32 *toAddr, u8 *toLsbPos, u8 *toWidth)
{
@ -385,6 +368,7 @@ static void extract_from_mnemonic(u32 regAddr, u8 lsbPos, u8 width,
if (toWidth)
*toWidth = width;
}
#endif
static int firmware_is_alive(struct mxl *state)
{
@ -397,6 +381,8 @@ static int firmware_is_alive(struct mxl *state)
return 0;
if (hb1 == hb0)
return 0;
pr_info("mxl5xx: Hydra FW alive. Hail!\n");
return 1;
}
@ -470,9 +456,9 @@ static int CfgDemodAbortTune(struct mxl *state)
&cmdBuff[0]);
}
#if 0
static int reset_fec_counter(struct mxl *state)
{
MXL_HYDRA_DEMOD_ABORT_TUNE_T abortTuneCmd;
u32 demodIndex = (u32) state->demod;
u8 cmdSize = sizeof(u32);
u8 cmdBuff[MXL_HYDRA_OEM_MAX_CMD_BUFF_LEN];
@ -482,6 +468,7 @@ static int reset_fec_counter(struct mxl *state)
return send_command(state, cmdSize + MXL_HYDRA_CMD_HEADER_SIZE,
&cmdBuff[0]);
}
#endif
static int send_master_cmd(struct dvb_frontend *fe,
struct dvb_diseqc_master_cmd *cmd)
@ -1118,8 +1105,6 @@ static int firmware_download(struct mxl *state, u8 *mbin, u32 mbin_len)
if (!firmware_is_alive(state))
return -1;
pr_info("mxl5xx: Hydra FW alive. Hail!\n");
/* sometimes register values are wrong shortly
after first heart beats */
msleep(50);
@ -1437,6 +1422,7 @@ static int config_ts(struct mxl *state, MXL_HYDRA_DEMOD_ID_E demodId,
{XPT_NCO_COUNT_MIN4}, {XPT_NCO_COUNT_MIN5},
{XPT_NCO_COUNT_MIN6}, {XPT_NCO_COUNT_MIN7} };
#if 0
MXL_REG_FIELD_T mxl561_xpt_ts_sync[MXL_HYDRA_DEMOD_ID_6] = {
{PAD_MUX_DIGIO_25_PINMUX_SEL}, {PAD_MUX_DIGIO_20_PINMUX_SEL},
{PAD_MUX_DIGIO_17_PINMUX_SEL}, {PAD_MUX_DIGIO_11_PINMUX_SEL},
@ -1445,6 +1431,7 @@ static int config_ts(struct mxl *state, MXL_HYDRA_DEMOD_ID_E demodId,
{PAD_MUX_DIGIO_26_PINMUX_SEL}, {PAD_MUX_DIGIO_19_PINMUX_SEL},
{PAD_MUX_DIGIO_18_PINMUX_SEL}, {PAD_MUX_DIGIO_10_PINMUX_SEL},
{PAD_MUX_DIGIO_09_PINMUX_SEL}, {PAD_MUX_DIGIO_02_PINMUX_SEL}};
#endif
demodId = state->base->ts_map[demodId];
@ -1609,6 +1596,7 @@ static int config_mux(struct mxl *state)
return 0;
}
#if 0
static int config_dis(struct mxl *state, u32 id)
{
MXL_HYDRA_DISEQC_ID_E diseqcId = id;
@ -1630,6 +1618,7 @@ static int config_dis(struct mxl *state, u32 id)
return send_command(state, cmdSize + MXL_HYDRA_CMD_HEADER_SIZE,
&cmdBuff[0]);
}
#endif
static int load_fw(struct mxl *state, struct mxl5xx_cfg *cfg)
{

View File

@ -3644,7 +3644,6 @@ static int stv090x_read_status(struct dvb_frontend *fe, enum fe_status *status)
{
u16 val;
u32 ber;
stv090x_read_cnr(fe, &val);
stv090x_read_signal_strength(fe, &val);
@ -3657,7 +3656,7 @@ static int stv090x_read_status(struct dvb_frontend *fe, enum fe_status *status)
static int stv090x_read_ber(struct dvb_frontend *fe, u32 *ber)
{
struct stv090x_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
//struct dtv_frontend_properties *p = &fe->dtv_property_cache;
u32 reg, h, m, l;
enum fe_status status;
@ -5075,7 +5074,7 @@ static int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, u8 dir,
static int stv090x_get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p)
{
struct stv090x_state *state = fe->demodulator_priv;
u8 tmp;
//u8 tmp;
u32 reg = 0;
if (state->rec_mode == 2) {

View File

@ -150,10 +150,12 @@ static int write_reg(struct stv *state, u16 reg, u8 val)
return (i2c_transfer(state->base->i2c, &msg, 1) == 1) ? 0 : -1;
}
#if 0
static int write_reg_off(struct stv *state, u16 reg, u8 val)
{
return write_reg(state, reg + state->regoff, val);
}
#endif
static inline int i2c_read_regs16(struct i2c_adapter *adapter, u8 adr,
u16 reg, u8 *val, int len)
@ -1639,6 +1641,7 @@ static int recv_slave_reply(struct dvb_frontend *fe,
static int send_burst(struct dvb_frontend *fe, enum fe_sec_mini_cmd burst)
{
#if 0
struct stv *state = fe->demodulator_priv;
u8 value;
@ -1653,6 +1656,7 @@ static int send_burst(struct dvb_frontend *fe, enum fe_sec_mini_cmd burst)
set_reg(DISTXFIFO, value);
set_reg(DISTXCFG, 0x3a);
wait_dis(state, 0x20, 0x20);
#endif
return 0;
}

View File

@ -100,12 +100,12 @@ static int read_reg(struct stv *state, u8 reg, u8 *val)
return i2c_read(state->i2c, state->adr, &reg, 1, val, 1);
}
#if 0
static int read_regs(struct stv *state, u8 reg, u8 *val, int len)
{
return i2c_read(state->i2c, state->adr, &reg, 1, val, len);
}
#if 0
static void dump_regs(struct stv *state)
{
u8 d[11], *c = &state->reg[0];

View File

@ -32,6 +32,16 @@ struct dvb_mod_channel_params {
#define MODULATOR_GAIN 35
#define MODULATOR_RESET 36
#define MODULATOR_STATUS 37
#define MODULATOR_INFO 38
#define MODULATOR_OUTPUT_ARI 64
#define MODULATOR_OUTPUT_RATE 65
enum mod_output_rate {
SYS_DVBT_6 = 0,
SYS_DVBT_7,
SYS_DVBT_8,
SYS_ISDBT_6 = 16,
};
#endif /*_UAPI_DVBMOD_H_*/

View File

@ -13,11 +13,11 @@ install: all
$(CC) $(CFLAGS) -fPIC -c $<
dddvb_test: dddvb_test.o
$(CC) -o dddvb_test $< -L ./src -l dddvb -l pthread
$(CC) -o dddvb_test $< -L ./src -l dddvb -l pthread -l dvben50221 -l dvbapi -l ucsi
ddzap: ddzap.o
$(CC) -o ddzap $< -L ./src -l dddvb -l pthread
$(CC) -o ddzap $< -L ./src -l dddvb -l pthread -l dvben50221 -l dvbapi -l ucsi
clean:
make -C ./src clean
rm *.o
-rm -f *.o

View File

@ -24,7 +24,8 @@ int main(int argc, char **argv)
struct dddvb_fe *fe;
struct dddvb_params p;
uint32_t bandwidth = 8000000, frequency = 0, symbol_rate = 0, pol = DDDVB_UNDEF;
uint32_t id = DDDVB_UNDEF, pls = DDDVB_UNDEF, num = DDDVB_UNDEF;
uint32_t id = DDDVB_UNDEF, pls = DDDVB_UNDEF, num = DDDVB_UNDEF, source = 0;
uint32_t verbosity = 0;
enum fe_code_rate fec = FEC_AUTO;
enum fe_delivery_system delsys = ~0;
char *config = "config/";
@ -38,16 +39,18 @@ int main(int argc, char **argv)
{"frequency", required_argument, 0, 'f'},
{"bandwidth", required_argument, 0, 'b'},
{"symbolrate", required_argument, 0, 's'},
{"source", required_argument, 0, 'l'},
{"delsys", required_argument, 0, 'd'},
{"id", required_argument, 0, 'i'},
{"pls", required_argument, 0, 'g'},
{"root", required_argument, 0, 'r'},
{"num", required_argument, 0, 'n'},
{"verbosity", required_argument, 0, 'v'},
{"help", no_argument , 0, 'h'},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv,
"c:i:f:s:d:p:hg:r:n:b:",
"c:i:f:s:d:p:hg:r:n:b:l:v:",
long_options, &option_index);
if (c==-1)
break;
@ -65,6 +68,12 @@ int main(int argc, char **argv)
case 's':
symbol_rate = strtoul(optarg, NULL, 0);
break;
case 'l':
source = strtoul(optarg, NULL, 0);
break;
case 'v':
verbosity = strtoul(optarg, NULL, 0);
break;
case 'g':
pls = strtoul(optarg, NULL, 0);
break;
@ -102,7 +111,14 @@ int main(int argc, char **argv)
pol = 0;
break;
case 'h':
printf("no help yet\n");
printf("ddzap [-d delivery_system] [-p polarity] [-c config_dir] [-f frequency(Hz)]\n"
" [-b bandwidth(Hz)] [-s symbol_rate(Hz)]\n"
" [-g gold_code] [-r root_code] [-i id] [-n device_num]\n"
"\n"
" delivery_system = C,S,S2,T,T2,J83B,ISDBC,ISDBT\n"
" polarity = h,v\n"
" polarity = h,v\n"
"\n");
exit(-1);
default:
break;
@ -124,7 +140,7 @@ int main(int argc, char **argv)
break;
}
dd = dddvb_init(config, 0);//0xffff);
dd = dddvb_init(config, verbosity);
if (!dd) {
printf("dddvb_init failed\n");
exit(-1);
@ -141,6 +157,7 @@ int main(int argc, char **argv)
}
dddvb_param_init(&p);
dddvb_set_frequency(&p, frequency);
dddvb_set_src(&p, source);
dddvb_set_bandwidth(&p, bandwidth);
dddvb_set_symbol_rate(&p, symbol_rate);
dddvb_set_polarization(&p, pol);
@ -148,6 +165,12 @@ int main(int argc, char **argv)
dddvb_set_id(&p, id);
dddvb_set_pls(&p, pls);
dddvb_dvb_tune(fe, &p);
{
uint8_t ts[188];
dddvb_ca_write(dd, 0, ts, 188);
}
while (1) {
fe_status_t stat;
int64_t str, cnr;

View File

@ -5,10 +5,10 @@ all: libdddvb.so.1.0.1
%.o: %.c
$(CC) $(LIB_FLAGS) $(CFLAGS) -c $<
libdddvb.a: dvb.o dddvb.o tools.o config.o
libdddvb.a: dvb.o dddvb.o tools.o config.o ca.o
$(AR) -cvq libdddvb.a $^
libdddvb.so.1.0.1: dvb.o dddvb.o tools.o config.o
libdddvb.so.1.0.1: dvb.o dddvb.o tools.o config.o ca.o
$(CC) $(LIB_FLAGS) $(CFLAGS) -shared -Wl,-soname,libdddvb.so.1 -o libdddvb.so.1.0.1 $^ -lc
ln -sf libdddvb.so.1.0.1 libdddvb.so.1
ln -sf libdddvb.so.1.0.1 libdddvb.so
@ -17,4 +17,4 @@ dddvb_test: dddvb_test.o
$(CC) -o dddvb_test $< -L . -l dddvb
clean:
rm *.o
-rm -f *.o

645
lib/src/ca.c Normal file
View File

@ -0,0 +1,645 @@
#include "libdddvb.h"
#include "dddvb.h"
#include "tools.h"
#include "debug.h"
#include <linux/dvb/dmx.h>
#include <linux/dvb/frontend.h>
#include <linux/dvb/video.h>
#include <linux/dvb/net.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <net/if.h>
#include <net/ethernet.h>
#include <net/if_arp.h>
#include <netinet/tcp.h>
#define MMI_STATE_CLOSED 0
#define MMI_STATE_OPEN 1
#define MMI_STATE_ENQ 2
#define MMI_STATE_MENU 3
int set_nonblock(int fd)
{
int fl = fcntl(fd, F_GETFL);
if (fl < 0)
return fl;
return fcntl(fd, F_SETFL, fl | O_NONBLOCK);
}
int streamsock(const char *port, int family, struct sockaddr *sadr)
{
int one=1, sock;
struct addrinfo *ais, *ai, hints = {
.ai_flags = AI_PASSIVE,
.ai_family = family,
.ai_socktype = SOCK_STREAM,
.ai_protocol = 0, .ai_addrlen = 0,
.ai_addr = NULL, .ai_canonname = NULL, .ai_next = NULL,
};
if (getaddrinfo(NULL, port, &hints, &ais) < 0)
return -1;
for (ai = ais; ai; ai = ai->ai_next) {
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (sock == -1)
continue;
if (!setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) &&
!bind(sock, ai->ai_addr, ai->ai_addrlen)) {
*sadr = *ai->ai_addr;
break;
}
close(sock);
sock = -1;
}
freeaddrinfo(ais);
return sock;
}
static int ai_callback(void *arg, uint8_t slot_id, uint16_t session_number,
uint8_t application_type, uint16_t application_manufacturer,
uint16_t manufacturer_code, uint8_t menu_string_length,
uint8_t *menu_string)
{
struct dddvb_ca *ca = arg;
dbgprintf(DEBUG_CA, "Application type: %02x\n", application_type);
dbgprintf(DEBUG_CA, "Application manufacturer: %04x\n", application_manufacturer);
dbgprintf(DEBUG_CA, "Manufacturer code: %04x\n", manufacturer_code);
dbgprintf(DEBUG_CA, "Menu string: %.*s\n", menu_string_length, menu_string);
return 0;
}
static int ca_info_callback(void *arg, uint8_t slot_id, uint16_t snum,
uint32_t id_count, uint16_t *ids)
{
struct dddvb_ca *ca = arg;
uint32_t i;
dbgprintf(DEBUG_CA, "CAM supports the following ca system ids:\n");
for (i = 0; i < id_count; i++) {
dbgprintf(DEBUG_CA, " 0x%04x\n", ids[i]);
}
ca->resource_ready = 1;
return 0;
}
#if 0
static int handle_pmt(struct dvbca *ca, uint8_t *buf, int size)
{
int listmgmt = CA_LIST_MANAGEMENT_ONLY;
uint8_t capmt[4096];
struct section *section = section_codec(buf, size);
struct section_ext *section_ext = section_ext_decode(section, 0);
struct mpeg_pmt_section *pmt = mpeg_pmt_section_codec(section_ext);
dbgprintf(DEBUG_CA, "handle pmt\n");
if (section_ext->version_number == ca->ca_pmt_version &&
ca->pmt == ca->pmt_old)
return;
if (ca->pmt != ca->pmt_old) {
ca->pmt_old = ca->pmt;
ca->sentpmt = 0;
}
if (ca->resource_ready) {
ca->data_pmt_version = pmt->head.version_number;
if (ca->sentpmt) {
listmgmt = CA_LIST_MANAGEMENT_UPDATE;
//return;
}
ca->sentpmt = 1;
dbgprintf(DEBUG_CA, "set ca_pmt\n");
if ((size = en50221_ca_format_pmt(pmt, capmt, sizeof(capmt), ca->moveca, listmgmt,
CA_PMT_CMD_ID_OK_DESCRAMBLING)) < 0) {
dbgprintf(DEBUG_CA, "Failed to format PMT\n");
return -1;
}
if (en50221_app_ca_pmt(ca->stdcam->ca_resource, ca->stdcam->ca_session_number, capmt, size)) {
dbgprintf(DEBUG_CA, "Failed to send PMT\n");
return -1;
}
}
}
#endif
#if 0
static void handle_tdt(struct dddvb_ca *ca)
{
struct section *section;
struct dvb_tdt_section *tdt;
uint8_t sec[4096];
time_t dvb_time;
int len;
if (ca->stdcam == NULL)
return;
if (ca->stdcam->dvbtime == NULL)
return;
len = getsec(ca->input, 0x14, 0, 0x70, sec);
if (len < 0)
return;
dbgprintf(DEBUG_CA, "got tdt\n");
section = section_codec(sec, len);
if (section == NULL)
return;
tdt = dvb_tdt_section_codec(section);
if (tdt == NULL)
return;
dvb_time = dvbdate_to_unixtime(tdt->utc_time);
dbgprintf(DEBUG_CA, "set dvbtime\n");
if (ca->stdcam->dvbtime)
ca->stdcam->dvbtime(ca->stdcam, dvb_time);
}
#endif
static int handle_pmts(struct dddvb_ca *ca)
{
int listmgmt = CA_LIST_MANAGEMENT_ONLY;
uint8_t sec[4096], capmt[4096];
struct section *section;
struct section_ext *section_ext;
struct mpeg_pmt_section *pmt;
int i, size, num, len;
if (!ca->resource_ready)
return 0;
dbgprintf(DEBUG_CA, "handle pmts\n");
for (i = num = 0; i < MAX_PMT; i++)
if (ca->pmt[i])
num++;
for (i = 0; i < num; i++) {
len = -1;//getsec(ca->input, ca->pmt[i] & 0xffff, ca->pmt[i] >> 16, 2, sec);
if (len < 0)
continue;
section = section_codec(sec, len);
section_ext = section_ext_decode(section, 0);
pmt = mpeg_pmt_section_codec(section_ext);
ca->ca_pmt_version[i] = section_ext->version_number;
if (ca->sentpmt) {
//return 0;
listmgmt = CA_LIST_MANAGEMENT_UPDATE;
} else {
listmgmt = CA_LIST_MANAGEMENT_ONLY;
if (num > 1) {
listmgmt = CA_LIST_MANAGEMENT_MORE;
if (i == 0)
listmgmt = CA_LIST_MANAGEMENT_FIRST;
if (i == num - 1)
listmgmt = CA_LIST_MANAGEMENT_LAST;
}
}
dbgprintf(DEBUG_CA, "set ca_pmt\n");
if ((size = en50221_ca_format_pmt(pmt, capmt, sizeof(capmt), ca->moveca, listmgmt,
CA_PMT_CMD_ID_OK_DESCRAMBLING)) < 0) {
dbgprintf(DEBUG_CA, "Failed to format PMT\n");
return -1;
}
//dump(capmt, size);
if (en50221_app_ca_pmt(ca->stdcam->ca_resource, ca->stdcam->ca_session_number, capmt, size)) {
dbgprintf(DEBUG_CA, "Failed to send PMT\n");
return -1;
}
}
if (num)
ca->sentpmt = 1;
return 0;
}
static int set_pmts(struct dddvb_ca *ca, uint8_t **pmts)
{
int listmgmt = CA_LIST_MANAGEMENT_ONLY;
uint8_t sec[4096], capmt[4096];
struct section *section;
struct section_ext *section_ext;
struct mpeg_pmt_section *pmt;
int i, size, num, len;
if (!ca->resource_ready)
return -EBUSY;
for (i = 0; i < MAX_PMT; i++)
if (!pmts[i])
break;
num = i;
dbgprintf(DEBUG_CA, "handle %d pmts\n", num);
for (i = 0; i < num; i++) {
memcpy(sec, pmts[i], 3);
len = ((sec[1] & 0x0f) << 8) | sec[2];
len += 3;
memcpy(sec, pmts[i], len);
section = section_codec(sec, len);
section_ext = section_ext_decode(section, 0);
pmt = mpeg_pmt_section_codec(section_ext);
ca->ca_pmt_version[i] = section_ext->version_number;
if (ca->sentpmt) {
//return 0;
listmgmt = CA_LIST_MANAGEMENT_UPDATE;
} else {
listmgmt = CA_LIST_MANAGEMENT_ONLY;
if (num > 1) {
listmgmt = CA_LIST_MANAGEMENT_MORE;
if (i == 0)
listmgmt = CA_LIST_MANAGEMENT_FIRST;
if (i == num - 1)
listmgmt = CA_LIST_MANAGEMENT_LAST;
}
}
dbgprintf(DEBUG_CA, "set ca_pmt\n");
if ((size = en50221_ca_format_pmt(pmt, capmt, sizeof(capmt), ca->moveca, listmgmt,
CA_PMT_CMD_ID_OK_DESCRAMBLING)) < 0) {
dbgprintf(DEBUG_CA, "Failed to format PMT\n");
return -1;
}
//dump(capmt, size);
if (en50221_app_ca_pmt(ca->stdcam->ca_resource, ca->stdcam->ca_session_number, capmt, size)) {
dbgprintf(DEBUG_CA, "Failed to send PMT\n");
return -1;
}
}
if (num)
ca->sentpmt = 1;
return 0;
}
static void proc_csock_msg(struct dddvb_ca *ca, uint8_t *buf, int len)
{
if (*buf == '\r') {
return;
} else if (*buf == '\n') {
switch(ca->mmi_state) {
case MMI_STATE_CLOSED:
case MMI_STATE_OPEN:
if ((ca->mmi_bufp == 0) && (ca->resource_ready)) {
en50221_app_ai_entermenu(ca->stdcam->ai_resource,
ca->stdcam->ai_session_number);
}
break;
case MMI_STATE_ENQ:
if (ca->mmi_bufp == 0) {
en50221_app_mmi_answ(ca->stdcam->mmi_resource,
ca->stdcam->mmi_session_number,
MMI_ANSW_ID_CANCEL, NULL, 0);
} else {
en50221_app_mmi_answ(ca->stdcam->mmi_resource,
ca->stdcam->mmi_session_number,
MMI_ANSW_ID_ANSWER,
ca->mmi_buf, ca->mmi_bufp);
}
ca->mmi_state = MMI_STATE_OPEN;
break;
case MMI_STATE_MENU:
ca->mmi_buf[ca->mmi_bufp] = 0;
en50221_app_mmi_menu_answ(ca->stdcam->mmi_resource,
ca->stdcam->mmi_session_number,
atoi(ca->mmi_buf));
ca->mmi_state = MMI_STATE_OPEN;
break;
}
ca->mmi_bufp = 0;
} else {
if (ca->mmi_bufp < (sizeof(ca->mmi_buf) - 1)) {
ca->mmi_buf[ca->mmi_bufp++] = *buf;
}
}
}
static int proc_csock(struct dddvb_ca *ca)
{
uint8_t buf[1024];
int len, i, res;
if (ca->stdcam == NULL)
return -1;
while ((len = recv(ca->sock, buf, 1, 0)) >= 0) {
if (len == 0)
goto release;
if (len < 0) {
if (errno != EAGAIN)
goto release;
return 0;
}
proc_csock_msg(ca, buf, len);
}
return 0;
release:
close(ca->sock);
ca->sock = -1;
return -1;
}
static void handle_ci(struct dddvb_ca *ca)
{
uint8_t sec[4096];
uint32_t pmt_count, tdt_count;
int len;
int sock, i;
struct sockaddr sadr;
char port[6];
snprintf(port, sizeof(port), "%u", (uint16_t) (8888 + ca->nr));
sock = streamsock(port, AF_INET, &sadr);
if (listen(sock, 4) < 0) {
dbgprintf(DEBUG_CA, "listen error");
return;
}
ca->sock = -1;
while (1) {//!ca->exit) {
struct timeval timeout;
uint32_t count = 0;
int num;
int mfd;
fd_set fds;
timeout.tv_sec = 0;
timeout.tv_usec = 200000;
FD_ZERO(&fds);
if (ca->sock < 0) {
FD_SET(sock, &fds);
num = select(sock + 1, &fds, NULL, NULL, &timeout);
} else {
FD_SET(ca->sock, &fds);
num = select(ca->sock + 1, &fds, NULL, NULL, &timeout);
}
if (num > 0) {
if (ca->sock < 0) {
if (FD_ISSET(sock, &fds)) {
socklen_t len;
struct sockaddr cadr;
ca->sock = accept(sock, &cadr, &len);
if (ca->sock >= 0) {
set_nonblock(ca->sock);
}
}
} else {
if (FD_ISSET(ca->sock, &fds)) {
proc_csock(ca);
}
}
}
pthread_mutex_lock(&ca->mutex);
if (!ca->state) {
pthread_mutex_unlock(&ca->mutex);
continue;
}
if (ca->setpmt) {
dbgprintf(DEBUG_CA, "got new PMT %08x\n", ca->pmt_new);
memcpy(ca->pmt, ca->pmt_new, sizeof(ca->pmt));
memset(ca->pmt_old, 0, sizeof(ca->pmt_old));
for (i = 0; i < MAX_PMT; i++)
ca->ca_pmt_version[i] = -1;
ca->sentpmt = 0;
ca->setpmt = 0;
pmt_count = 0;
tdt_count = 0;
}
pthread_mutex_unlock(&ca->mutex);
/*
if (!ca->sentpmt)
handle_pmts(ca);
else {
pmt_count++;
if (pmt_count == 10) {
//handle_pmts(ca);
pmt_count = 0;
}
}
*/
tdt_count++;
if (tdt_count == 10) {
//handle_tdt(ca);
tdt_count = 0;
}
}
}
int set_pmt(struct dddvb_ca *ca, uint32_t *pmt)
{
dbgprintf(DEBUG_CA, "set_pmt %08x %08x %08x\n", pmt[0], pmt[1], pmt[2]);
pthread_mutex_lock(&ca->mutex);
ca->setpmt = 1;
memcpy(ca->pmt_new, pmt, sizeof(ca->pmt_new));
pthread_mutex_unlock(&ca->mutex);
return 0;
}
static void ci_poll(struct dddvb_ca *ca)
{
while (!ca->dd->exit) {
ca->stdcam->poll(ca->stdcam);
}
}
static int mmi_close_callback(void *arg, uint8_t slot_id, uint16_t snum,
uint8_t cmd_id, uint8_t delay)
{
struct dddvb_ca *ca = arg;
ca->mmi_state = MMI_STATE_CLOSED;
return 0;
}
static int mmi_display_control_callback(void *arg, uint8_t slot_id, uint16_t snum,
uint8_t cmd_id, uint8_t mmi_mode)
{
struct dddvb_ca *ca = arg;
struct en50221_app_mmi_display_reply_details reply;
if (cmd_id != MMI_DISPLAY_CONTROL_CMD_ID_SET_MMI_MODE) {
en50221_app_mmi_display_reply(ca->stdcam->mmi_resource, snum,
MMI_DISPLAY_REPLY_ID_UNKNOWN_CMD_ID, &reply);
return 0;
}
// we only support high level mode
if (mmi_mode != MMI_MODE_HIGH_LEVEL) {
en50221_app_mmi_display_reply(ca->stdcam->mmi_resource, snum,
MMI_DISPLAY_REPLY_ID_UNKNOWN_MMI_MODE, &reply);
return 0;
}
reply.u.mode_ack.mmi_mode = mmi_mode;
en50221_app_mmi_display_reply(ca->stdcam->mmi_resource, snum,
MMI_DISPLAY_REPLY_ID_MMI_MODE_ACK, &reply);
ca->mmi_state = MMI_STATE_OPEN;
return 0;
}
static int mmi_enq_callback(void *arg, uint8_t slot_id, uint16_t snum,
uint8_t blind_answer, uint8_t expected_answer_length,
uint8_t *text, uint32_t text_size)
{
struct dddvb_ca *ca = arg;
if (ca->sock >= 0) {
sendstring(ca->sock, "%.*s: ", text_size, text);
}
//mmi_enq_blind = blind_answer;
//mmi_enq_length = expected_answer_length;
ca->mmi_state = MMI_STATE_ENQ;
return 0;
}
static int mmi_menu_callback(void *arg, uint8_t slot_id, uint16_t snum,
struct en50221_app_mmi_text *title,
struct en50221_app_mmi_text *sub_title,
struct en50221_app_mmi_text *bottom,
uint32_t item_count, struct en50221_app_mmi_text *items,
uint32_t item_raw_length, uint8_t *items_raw)
{
uint32_t i;
struct dddvb_ca *ca = arg;
if (ca->sock >= 0) {
if (title->text_length)
sendstring(ca->sock, "%.*s\n", title->text_length, title->text);
if (sub_title->text_length)
sendstring(ca->sock, "%.*s\n", sub_title->text_length, sub_title->text);
for (i = 0; i < item_count; i++)
sendstring(ca->sock, "%i. %.*s\n", i + 1, items[i].text_length, items[i].text);
if (bottom->text_length)
sendstring(ca->sock, "%.*s\n", bottom->text_length, bottom->text);
}
ca->mmi_state = MMI_STATE_MENU;
return 0;
}
static int init_ca_stack(struct dddvb_ca *ca)
{
ca->tl = en50221_tl_create(1, 16);
if (ca->tl == NULL) {
dbgprintf(DEBUG_CA, "Failed to create transport layer\n");
return -1;
}
ca->sl = en50221_sl_create(ca->tl, 16);
if (ca->sl == NULL) {
dbgprintf(DEBUG_CA, "Failed to create session layer\n");
en50221_tl_destroy(ca->tl);
return -1;
}
ca->stdcam = en50221_stdcam_llci_create(ca->fd, 0, ca->tl, ca->sl);
if (!ca->stdcam) {
dbgprintf(DEBUG_CA, "Failed to create stdcam\n");
en50221_sl_destroy(ca->sl);
en50221_tl_destroy(ca->tl);
return -1;
}
if (ca->stdcam->ai_resource) {
en50221_app_ai_register_callback(ca->stdcam->ai_resource, ai_callback, ca);
}
if (ca->stdcam->ca_resource) {
en50221_app_ca_register_info_callback(ca->stdcam->ca_resource, ca_info_callback, ca);
}
if (ca->stdcam->mmi_resource) {
en50221_app_mmi_register_close_callback(ca->stdcam->mmi_resource, mmi_close_callback, ca);
en50221_app_mmi_register_display_control_callback(ca->stdcam->mmi_resource,
mmi_display_control_callback, ca);
en50221_app_mmi_register_enq_callback(ca->stdcam->mmi_resource, mmi_enq_callback, ca);
en50221_app_mmi_register_menu_callback(ca->stdcam->mmi_resource, mmi_menu_callback, ca);
en50221_app_mmi_register_list_callback(ca->stdcam->mmi_resource, mmi_menu_callback, ca);
} else {
dbgprintf(DEBUG_CA,
"CAM Menus are not supported by this interface hardware\n");
}
return 0;
}
static int init_ca(struct dddvb *dd, int a, int f, int fd)
{
struct dddvb_ca *ca;
char fname[80];
ca = &dd->dvbca[dd->dvbca_num];
ca->dd = dd;
ca->anum = a;
ca->fnum = f;
ca->nr = dd->dvbca_num + 1;
ca->fd = fd;
pthread_mutex_init(&ca->mutex, 0);
init_ca_stack(ca);
pthread_create(&ca->poll_pt, NULL, (void *) ci_poll, ca);
pthread_create(&ca->pt, NULL, (void *) handle_ci, ca);
sprintf(fname, "/dev/dvb/adapter%d/ci%d", a, f);
ca->ci_wfd = open(fname, O_WRONLY);
ca->ci_rfd = open(fname, O_RDONLY | O_NONBLOCK);
dd->dvbca_num++;
return 0;
}
int dddvb_ca_write(struct dddvb *dd, uint32_t nr, uint8_t *buf, uint32_t len)
{
struct dddvb_ca *ca = &dd->dvbca[nr];
return write(ca->ci_wfd, buf, len);
}
int dddvb_ca_read(struct dddvb *dd, uint32_t nr, uint8_t *buf, uint32_t len)
{
struct dddvb_ca *ca = &dd->dvbca[nr];
return read(ca->ci_rfd, buf, len);
}
int dddvb_ca_set_pmts(struct dddvb *dd, uint32_t nr, uint8_t **pmts)
{
struct dddvb_ca *ca = &dd->dvbca[nr];
dbgprintf(DEBUG_CA, "ca_set_pmt\n");
return set_pmts(ca, pmts);
}
int scan_dvbca(struct dddvb *dd)
{
int a, f, fd;
char fname[80];
for (a = 0; a < 16; a++) {
for (f = 0; f < 16; f++) {
sprintf(fname, "/dev/dvb/adapter%d/ca%d", a, f);
fd = open(fname, O_RDWR);
if (fd >= 0) {
init_ca(dd, a, f, fd);
//close(fd);
}
}
}
dbgprintf(DEBUG_CA, "Found %d CA interfaces\n", dd->dvbca_num);
}

View File

@ -3,7 +3,6 @@
#include "debug.h"
#include <string.h>
LIBDDDVB_EXPORTED uint32_t dddvb_debug;
LIBDDDVB_EXPORTED struct dddvb *global_dd = NULL;
LIBDDDVB_EXPORTED pthread_mutex_t dddvb_mutex = PTHREAD_MUTEX_INITIALIZER;

View File

@ -13,7 +13,10 @@
#include <linux/dvb/net.h>
#include <libdvben50221/en50221_stdcam.h>
#define DDDVB_MAX_DVB_FE 256
#define DDDVB_MAX_DVB_CA 256
#define DDDVB_MAX_SOURCE 4
@ -74,6 +77,7 @@ struct dddvb_fe {
uint32_t quality;
int64_t strength;
int64_t cnr;
int64_t ber;
int first;
uint32_t tune;
@ -85,6 +89,44 @@ struct dddvb_fe {
struct dddvb_status status;
};
struct dddvb_ca {
struct dddvb *dd;
struct osstrm *stream;
int fd;
int ci_rfd;
int ci_wfd;
uint32_t type;
int anum;
int fnum;
int state;
int nr;
int input;
pthread_t pt;
pthread_t poll_pt;
pthread_mutex_t mutex;
struct en50221_transport_layer *tl;
struct en50221_session_layer *sl;
struct en50221_stdcam *stdcam;
int resource_ready;
int sentpmt;
int moveca;
int ca_pmt_version[MAX_PMT];
int data_pmt_version;
int setpmt;
uint32_t pmt[MAX_PMT];
uint32_t pmt_new[MAX_PMT];
uint32_t pmt_old[MAX_PMT];
int mmi_state;
uint8_t mmi_buf[16];
int mmi_bufp;
int sock;
};
struct dddvb {
pthread_mutex_t lock;
pthread_mutex_t uni_lock;
@ -103,7 +145,11 @@ struct dddvb {
uint32_t dvbfe_num;
uint32_t scif_type;
uint32_t dvbca_num;
int exit;
struct dddvb_fe dvbfe[DDDVB_MAX_DVB_FE];
struct dddvb_ca dvbca[DDDVB_MAX_DVB_CA];
};
int dddvb_dvb_init(struct dddvb *dd);
@ -112,7 +158,7 @@ int parse_config(struct dddvb *dd, char *name, char *sec,
void dddvb_fe_handle(struct dddvb_fe *fe);
int dddvb_fe_tune(struct dddvb_fe *fe, struct dddvb_params *p);
int dddvb_fe_start(struct dddvb_fe *fe);
int scan_dvbca(struct dddvb *dd);
#endif /* _DDDVB_H_ */

View File

@ -14,6 +14,7 @@ extern uint32_t dddvb_debug;
#define DEBUG_DVB 16
#define DEBUG_IGMP 32
#define DEBUG_SWITCH 64
#define DEBUG_CA 128
#define DEBUG_DEBUG 256

View File

@ -80,6 +80,24 @@ static int get_stat(int fd, uint32_t cmd, struct dtv_fe_stats *stats)
return 0;
}
static int get_stat_num(int fd, uint32_t cmd, struct dtv_fe_stats *stats, int num)
{
struct dtv_property p;
struct dtv_properties c;
int ret;
p.cmd = cmd;
c.num = num;
c.props = &p;
ret = ioctl(fd, FE_GET_PROPERTY, &c);
if (ret < 0) {
fprintf(stderr, "FE_GET_PROPERTY returned %d\n", ret);
return -1;
}
memcpy(stats, &p.u.st, num*sizeof(struct dtv_fe_stats));
return 0;
}
static int set_fe_input(struct dddvb_fe *fe, uint32_t fr,
@ -533,6 +551,9 @@ static int open_fe(struct dddvb_fe *fe)
return 0;
}
#include "dvb_quality.c"
static void get_stats(struct dddvb_fe *fe)
{
uint16_t sig = 0, snr = 0;
@ -545,7 +566,7 @@ static void get_stats(struct dddvb_fe *fe)
ioctl(fe->fd, FE_READ_STATUS, &stat);
fe->stat = stat;
fe->lock = (stat == 0x1f) ? 1 : 0;
//calc_lq(fe);
calc_lq(fe);
if (!get_stat(fe->fd, DTV_STAT_SIGNAL_STRENGTH, &st)) {
fe->strength = str = st.stat[0].svalue;
@ -886,6 +907,7 @@ int dddvb_dvb_init(struct dddvb *dd)
parse_config(dd, "", "scif", &scif_config);
set_lnb(dd, 0, 0, 9750000, 10600000, 11700000);
parse_config(dd, "", "LNB", &lnb_config);
scan_dvbca(dd);
}

388
lib/src/dvb_quality.c Normal file
View File

@ -0,0 +1,388 @@
static int32_t Log10x100(uint32_t x)
{
static uint32_t LookupTable[100] = {
101157945, 103514217, 105925373, 108392691, 110917482,
113501082, 116144861, 118850223, 121618600, 124451461, // 800.5 - 809.5
127350308, 130316678, 133352143, 136458314, 139636836,
142889396, 146217717, 149623566, 153108746, 156675107, // 810.5 - 819.5
160324539, 164058977, 167880402, 171790839, 175792361,
179887092, 184077200, 188364909, 192752491, 197242274, // 820.5 - 829.5
201836636, 206538016, 211348904, 216271852, 221309471,
226464431, 231739465, 237137371, 242661010, 248313311, // 830.5 - 839.5
254097271, 260015956, 266072506, 272270131, 278612117,
285101827, 291742701, 298538262, 305492111, 312607937, // 840.5 - 849.5
319889511, 327340695, 334965439, 342767787, 350751874,
358921935, 367282300, 375837404, 384591782, 393550075, // 850.5 - 859.5
402717034, 412097519, 421696503, 431519077, 441570447,
451855944, 462381021, 473151259, 484172368, 495450191, // 860.5 - 869.5
506990708, 518800039, 530884444, 543250331, 555904257,
568852931, 582103218, 595662144, 609536897, 623734835, // 870.5 - 879.5
638263486, 653130553, 668343918, 683911647, 699841996,
716143410, 732824533, 749894209, 767361489, 785235635, // 880.5 - 889.5
803526122, 822242650, 841395142, 860993752, 881048873,
901571138, 922571427, 944060876, 966050879, 988553095, // 890.5 - 899.5
};
int32_t y = 800;
int i = 0;
if( x == 0 ) return 0;
if( x >= 1000000000 ) {
x /= 10;
y += 100;
}
while (x < 100000000 ) {
x *= 10;
y -= 100;
}
while ( i < 100 && x > LookupTable[i] ) i += 1;
y += i;
return y;
}
static int32_t berq_rs(uint32_t BERNumerator, uint32_t BERDenominator)
{
int32_t LogBER = Log10x100(BERDenominator) - Log10x100(BERNumerator);
int32_t BERQual = 100;
if ( BERNumerator == 0 )
return 100;
if (LogBER < 700) {
if (LogBER < 300)
BERQual = 0;
else
BERQual = (LogBER + 5) / 5 - 40;
}
return BERQual;
}
static int32_t berq_bch(uint32_t BERNumerator, uint32_t BERDenominator)
{
int32_t LogBER = Log10x100(BERDenominator) - Log10x100(BERNumerator);
int32_t BERQual = 100;
if (BERNumerator == 0 )
return 100;
if (LogBER < 700) {
if( LogBER < 400 )
BERQual = 0;
else
BERQual = 40;
}
return BERQual;
}
static uint32_t ber_quality(struct dddvb_fe *fe)
{
struct dtv_fe_stats ber;
get_stat(fe->fd, DTV_STAT_PRE_ERROR_BIT_COUNT, &ber);
get_stat(fe->fd, DTV_STAT_PRE_TOTAL_BIT_COUNT, &ber);
return 100;
}
static int32_t dvbsq(uint32_t snr, uint32_t fec,
uint32_t ber_num, uint32_t ber_den)
{
int32_t SignalToNoiseRel = -1000;
int32_t Quality = 0;
int32_t BERQuality = berq_rs(ber_num, ber_den);
// SNR Values for quasi errorfree reception from Nordig 2.2
static const int32_t DVBS_SN[] = {
// 1/2 2/3 3/4 5/6 7/8
0, 38, 56, 67, 0, 77, 0, 84
};
if (fec >= FEC_NONE && fec <= FEC_7_8 )
SignalToNoiseRel = snr / 100 - DVBS_SN[fec];
if( SignalToNoiseRel < -70 )
Quality = 0;
else if( SignalToNoiseRel < 30 )
Quality = ((SignalToNoiseRel + 70) * BERQuality) / 100;
else
Quality = BERQuality;
return Quality;
}
int32_t dvbs2q(int32_t snr, uint32_t fec, uint32_t mod,
uint32_t ber_num, uint32_t ber_den)
{
static const int32_t DVBS2_SN_QPSK[] = {
// 1/2 2/3 3/4 4/5 5/6 6/7 7/8 8/9 AUT 3/5 9/10 2/5
0, 20, 41, 50, 57, 62, 0, 0, 72, 0, 32, 74, 7,
};
static const int32_t DVBS2_SN_8PSK[] = {
// 1/2 2/3 3/4 4/5 5/6 6/7 7/8 8/9 AUT 3/5 9/10 2/5
0, 0, 76, 89, 0, 104, 0, 0, 117, 0, 65, 120, 0,
};
static const int32_t DVBS2_SN_16APSK[] = {
// 1/2 2/3 3/4 4/5 5/6 6/7 7/8 8/9 AUT 3/5 9/10 2/5
0, 0, 100, 112, 120, 126, 0, 0, 139, 0, 0, 141, 0,
};
static const int32_t DVBS2_SN_32APSK[] = {
// 1/2 2/3 3/4 4/5 5/6 6/7 7/8 8/9 AUT 3/5 9/10 2/5
0, 0, 0, 137, 146, 153, 0, 0, 167, 0, 0, 171, 0,
};
int32_t BERQuality = berq_bch(ber_num, ber_den);
int32_t Quality = 0;
int32_t SignalToNoiseRel = -1000, snc = 0;
if (fec > FEC_2_5 )
return 0;
switch (mod) {
case QPSK:
snc = DVBS2_SN_QPSK[fec];
break;
case PSK_8:
snc = DVBS2_SN_8PSK[fec];
break;
case APSK_16:
snc = DVBS2_SN_16APSK[fec];
break;
case APSK_32:
snc = DVBS2_SN_32APSK[fec];
break;
default:
return 0;
}
SignalToNoiseRel = snr / 100 - snc;
if (SignalToNoiseRel < -30 )
Quality = 0;
else if( SignalToNoiseRel < 30 )
Quality = ((SignalToNoiseRel + 30) * BERQuality) / 60;
else
Quality = 100;
return Quality;
}
static int32_t dvbcq(int32_t snr, uint32_t mod,
uint32_t ber_num, uint32_t ber_den)
{
int32_t SignalToNoiseRel = 0;
int32_t Quality = 0;
int32_t BERQuality = berq_rs(ber_num, ber_den);
switch (mod) {
case QAM_16: SignalToNoiseRel = snr - 200; break;
case QAM_32: SignalToNoiseRel = snr - 230; break;
case QAM_64: SignalToNoiseRel = snr - 260; break;
case QAM_128: SignalToNoiseRel = snr - 290; break;
case QAM_256: SignalToNoiseRel = snr - 320; break;
}
if (SignalToNoiseRel < -70)
Quality = 0;
else if (SignalToNoiseRel < 30)
Quality = ((SignalToNoiseRel + 70) * BERQuality) / 100;
else
Quality = BERQuality;
return Quality;
}
static int32_t dvbtq(int32_t snr, uint32_t mod, uint32_t fec,
uint32_t ber_num, uint32_t ber_den)
{
int32_t Quality = 0;
int32_t BERQuality = berq_rs(ber_num, ber_den);
int32_t SignalToNoiseRel = -1000, snc = 0;
// SNR Values for quasi error free reception from Nordig 2.2
static const int32_t DVBT_SN_QPSK[] = {
// 1/2 2/3 3/4 4/5 5/6 6/7 7/8 8/9 AUT 3/5 9/10 2/5
0, 51, 69, 79, 0, 89, 0, 97, 0, 0, 0, 0, 0,
};
static const int32_t DVBT_SN_QAM16[] = {
// 1/2 2/3 3/4 4/5 5/6 6/7 7/8 8/9 AUT 3/5 9/10 2/5
0, 108, 131, 146, 0, 156, 0, 160, 0, 0, 0, 0, 0,
};
static const int32_t DVBT_SN_QAM64[] = {
// 1/2 2/3 3/4 4/5 5/6 6/7 7/8 8/9 AUT 3/5 9/10 2/5
0, 165, 187, 202, 0, 216, 0, 225, 0, 0, 0, 0, 0,
};
if (fec > FEC_2_5 )
return 0;
switch (mod) {
case QPSK:
snc = DVBT_SN_QPSK[fec];
break;
case QAM_16:
snc = DVBT_SN_QAM16[fec];
break;
case QAM_64:
snc = DVBT_SN_QAM64[fec];
break;
default:
break;
}
SignalToNoiseRel = snr / 100 - snc;
if (SignalToNoiseRel < -70 )
Quality = 0;
else if (SignalToNoiseRel < 30)
Quality = ((SignalToNoiseRel + 70) * BERQuality)/100;
else
Quality = BERQuality;
return Quality;
}
static int32_t dvbt2q(int32_t snr, uint32_t mod, uint32_t fec, uint32_t trans, uint32_t pilot,
uint32_t ber_num, uint32_t ber_den)
{
int32_t Quality = 0;
int32_t BERQuality = berq_bch(ber_num, ber_den);
int32_t SignalToNoiseRel = -1000, snc = 0;
static const int32_t QE_SN_16K_QPSK[] = {
// 1/2 2/3 3/4 4/5 5/6 6/7 7/8 8/9 AUT 3/5 9/10 2/5 1/4 1/3
0, 32, 59, 68, 74, 80, 0, 0, 0, 0, 49, 0, 24, 0, 15 };
static const int32_t QE_SN_16K_16QAM[] = {
// 1/2 2/3 3/4 4/5 5/6 6/7 7/8 8/9 AUT 3/5 9/10 2/5 1/4 1/3
0, 82,116,130,136,141, 0, 0, 0, 0, 104, 0, 74, 0, 62 };
static const int32_t QE_SN_16K_64QAM[] = {
// 1/2 2/3 3/4 4/5 5/6 6/7 7/8 8/9 AUT 3/5 9/10 2/5 1/4 1/3
0,123,165,181,190,197, 0, 0, 0, 0, 151, 0,114, 0,101 };
static const int32_t QE_SN_16K_256QAM[] = {
// 1/2 2/3 3/4 4/5 5/6 6/7 7/8 8/9 AUT 3/5 9/10 2/5 1/4 1/3
0,164,211,232,246,255, 0, 0, 0, 0, 202, 0,153, 0,137 };
static const int32_t QE_SN_64K_QPSK[] = {
// 1/2 2/3 3/4 4/5 5/6 6/7 7/8 8/9 AUT 3/5 9/10 2/5 1/4 1/3
0, 35, 56, 66, 72, 77, 0, 0, 0, 0, 47, 0, 22, 0, 13 };
static const int32_t QE_SN_64K_16QAM[] = {
// 1/2 2/3 3/4 4/5 5/6 6/7 7/8 8/9 AUT 3/5 9/10 2/5 1/4 1/3
0, 87,114,125,133,138, 0, 0, 0, 0, 101, 0, 72, 0, 60 };
static const int32_t QE_SN_64K_64QAM[] = {
// 1/2 2/3 3/4 4/5 5/6 6/7 7/8 8/9 AUT 3/5 9/10 2/5 1/4 1/3
0,130,162,177,187,194, 0, 0, 0, 0, 148, 0,111, 0, 98 };
static const int32_t QE_SN_64K_256QAM[] = {
// 1/2 2/3 3/4 4/5 5/6 6/7 7/8 8/9 AUT 3/5 9/10 2/5 1/4 1/3
0,170,208,229,243,251, 0, 0, 0, 0, 194, 0,148, 0,132 };
if (trans == TRANSMISSION_MODE_16K) {
switch (mod) {
case QPSK:
snc = QE_SN_16K_QPSK[fec];
break;
case QAM_16:
snc = QE_SN_16K_16QAM[fec];
break;
case QAM_64:
snc = QE_SN_16K_64QAM[fec];
break;
case QAM_256:
snc = QE_SN_16K_256QAM[fec];
break;
default:
break;
}
}
if (trans == TRANSMISSION_MODE_C3780 + 1) { /* TRANSMISSION_MODE_64K */
switch (mod) {
case QPSK:
snc = QE_SN_64K_QPSK[fec];
break;
case QAM_16:
snc = QE_SN_64K_16QAM[fec];
break;
case QAM_64:
snc = QE_SN_64K_64QAM[fec];
break;
case QAM_256:
snc = QE_SN_64K_256QAM[fec];
break;
default:
break;
}
}
if (snc) {
SignalToNoiseRel = snr - snc;
#if 0 //FIXME
if (PilotPattern >= DVBT2_PP3 &&
PilotPattern <= DVBT2_PP4 )
SignalToNoiseRel += 5;
else if
( PilotPattern >= DVBT2_PP5 && PilotPattern <= DVBT2_PP8 )
SignalToNoiseRel += 10;
#endif
}
if( SignalToNoiseRel < -30 )
Quality = 0;
else if (SignalToNoiseRel < 30 )
Quality = ((SignalToNoiseRel + 30) * BERQuality)/60;
else
Quality = 100;
return Quality;
}
static void calc_lq(struct dddvb_fe *fe)
{
struct dtv_fe_stats st;
int64_t str, snr;
uint32_t mod, fec, ber_num, ber_den, trans, pilot = 0, quality = 0;
get_stat(fe->fd, DTV_STAT_SIGNAL_STRENGTH, &st);
str = st.stat[0].svalue;
dbgprintf(DEBUG_DVB, "fe%d: str=%lld\n", fe->nr, str);
fe->strength = str;
str = (str * 48) / 10000 + 344;
if (str < 0)
str = 0;
if (str > 255)
str = 255;
fe->level = str;
// str: 0-255: -25dbm = 224, -65dbm = 32
// qual: 0-15 15=BER<2*10^-4 PER<10^-7
get_stat(fe->fd, DTV_STAT_CNR, &st);
snr = st.stat[0].svalue;
fe->cnr = snr;
get_property(fe->fd, DTV_INNER_FEC, &fec);
fe->param.param[PARAM_FEC] = fec;
get_property(fe->fd, DTV_MODULATION, &mod);
fe->param.param[PARAM_MTYPE] = mod;
get_stat(fe->fd, DTV_STAT_PRE_ERROR_BIT_COUNT, &st);
ber_num = st.stat[0].uvalue;
get_stat(fe->fd, DTV_STAT_PRE_TOTAL_BIT_COUNT, &st);
ber_den = st.stat[0].uvalue;
dbgprintf(DEBUG_DVB, "fe%d: snr=%lld ber=%llu/%llu\n",
fe->nr, snr, ber_num, ber_den);
dbgprintf(DEBUG_DVB, "fe%d: fec=%u mod=%u\n", fe->nr, fec, mod);
switch (fe->n_param.param[PARAM_MSYS]) {
case SYS_DVBS:
quality = dvbsq(snr, fec, ber_num, ber_den);
break;
case SYS_DVBS2:
quality = dvbs2q(snr, fec, mod, ber_num, ber_den);
break;
case SYS_DVBC_ANNEX_A:
quality = dvbcq(snr, mod, ber_num, ber_den);
break;
case SYS_DVBT:
quality = dvbtq(snr, mod, fec, ber_num, ber_den);
break;
case SYS_DVBT2:
get_property(fe->fd, DTV_TRANSMISSION_MODE, &trans);
dbgprintf(DEBUG_DVB, "fe%d: trans=%u pilot=%u\n", fe->nr, trans, pilot);
quality = dvbt2q(snr, mod, fec, trans, pilot, ber_num, ber_den);
break;
case SYS_DVBC2:
break;
default:
break;
}
fe->quality = quality;
dbgprintf(DEBUG_DVB, "fe%d: level=%u quality=%u\n", fe->nr, fe->level, fe->quality);
}

View File

@ -60,6 +60,10 @@ LIBDDDVB_EXPORTED struct dddvb *dddvb_init(char *config, uint32_t flags);
LIBDDDVB_EXPORTED int dddvb_dvb_tune(struct dddvb_fe *fe, struct dddvb_params *p);
LIBDDDVB_EXPORTED struct dddvb_fe *dddvb_fe_alloc(struct dddvb *dd, uint32_t type);
LIBDDDVB_EXPORTED struct dddvb_fe *dddvb_fe_alloc_num(struct dddvb *dd, uint32_t type, uint32_t num);
LIBDDDVB_EXPORTED int dddvb_ca_write(struct dddvb *dd, uint32_t nr, uint8_t *buf, uint32_t len);
LIBDDDVB_EXPORTED int dddvb_ca_read(struct dddvb *dd, uint32_t nr, uint8_t *buf, uint32_t len);
LIBDDDVB_EXPORTED int dddvb_ca_set_pmts(struct dddvb *dd, uint32_t nr, uint8_t **pmts);
static inline void dddvb_set_frequency(struct dddvb_params *p, uint32_t freq) {
p->param[PARAM_FREQ] = freq;
@ -109,6 +113,14 @@ static inline int64_t dddvb_get_cnr(struct dddvb_fe *fe) {
return fe->cnr;
};
static inline int64_t dddvb_get_ber(struct dddvb_fe *fe) {
return fe->ber;
};
static inline uint32_t dddvb_get_quality(struct dddvb_fe *fe) {
return fe->quality;
};
static inline void dddvb_param_init(struct dddvb_params *p) {
int i;
@ -116,4 +128,10 @@ static inline void dddvb_param_init(struct dddvb_params *p) {
p->param[i] = DDDVB_UNDEF;
};
#if 0
static inline int dddvb_ca_write(struct dddvb *dd, uint32_t nr, uint8_t *buf, uint32_t len) {
return ca_write(dd, nr, buf, len);
};
#endif
#endif /* _LIBDDDVB_H_ */

View File

@ -1,4 +1,37 @@
#include "time.h"
#include <stdint.h>
#include <stdarg.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
int sendlen(int sock, char *buf, int len)
{
int done, todo;
for (todo = len; todo; todo -= done, buf += done)
if ((done = send(sock, buf, todo, 0)) < 0) {
printf("sendlen error\n");
return done;
}
return len;
}
int sendstring(int sock, char *fmt, ...)
{
int len;
uint8_t buf[2048];
va_list args;
va_start(args, fmt);
len = vsnprintf(buf, sizeof(buf), fmt, args);
if (len <= 0 || len >= sizeof(buf))
return 0;
sendlen(sock, buf, len);
va_end(args);
return len;
}
time_t mtime(time_t *t)
{

View File

@ -2,5 +2,7 @@
#define _DDDVB_TOOLS_H_
time_t mtime(time_t *t);
int sendlen(int sock, char *buf, int len);
int sendstring(int sock, char *fmt, ...);
#endif /* _DDDVB_TOOLS_H_ */