Created
February 8, 2017 13:19
-
-
Save athoik/5f755cabed0cfccea008d36e9f166e7b to your computer and use it in GitHub Desktop.
Simple Utility to query DVB API 5 statistics (with some code borrowed from other utilities)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <linux/dvb/version.h> | |
#include <linux/dvb/frontend.h> | |
#include <iostream> | |
#include <sstream> | |
#include <sys/ioctl.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <unistd.h> | |
#include <fcntl.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <errno.h> | |
using namespace std; | |
const char* getScale(int scale) | |
{ | |
if(scale == FE_SCALE_NOT_AVAILABLE) | |
return "FE_SCALE_NOT_AVAILABLE"; | |
else if(scale == FE_SCALE_RELATIVE) | |
return "FE_SCALE_RELATIVE"; | |
else if(scale == FE_SCALE_DECIBEL) | |
return "FE_SCALE_DECIBEL"; | |
else if(scale == FE_SCALE_COUNTER) | |
return "FE_SCALE_COUNTER"; | |
else | |
return "ERROR??"; | |
} | |
const char* getCMD(int cmd) | |
{ | |
if(cmd == DTV_STAT_CNR) | |
return "DTV_STAT_CNR"; | |
else if(cmd == DTV_STAT_SIGNAL_STRENGTH) | |
return "DTV_STAT_SIGNAL_STRENGTH"; | |
else if(cmd == DTV_STAT_ERROR_BLOCK_COUNT) | |
return "DTV_STAT_ERROR_BLOCK_COUNT"; | |
else if(cmd == DTV_STAT_PRE_ERROR_BIT_COUNT) | |
return "DTV_STAT_PRE_ERROR_BIT_COUNT"; | |
else if(cmd == DTV_STAT_PRE_TOTAL_BIT_COUNT) | |
return "DTV_STAT_PRE_TOTAL_BIT_COUNT"; | |
else if(cmd == DTV_STAT_POST_ERROR_BIT_COUNT) | |
return "DTV_STAT_POST_ERROR_BIT_COUNT"; | |
else if(cmd == DTV_STAT_POST_TOTAL_BIT_COUNT) | |
return "DTV_STAT_POST_TOTAL_BIT_COUNT"; | |
else if(cmd == DTV_STAT_ERROR_BLOCK_COUNT) | |
return "DTV_STAT_ERROR_BLOCK_COUNT"; | |
else if(cmd == DTV_STAT_TOTAL_BLOCK_COUNT) | |
return "DTV_STAT_TOTAL_BLOCK_COUNT"; | |
#if defined DTV_STATUS | |
else if(cmd == DTV_STATUS) | |
return "DTV_STATUS"; | |
else if(cmd == DTV_BER) | |
return "DTV_BER"; | |
else if(cmd == DTV_PER) | |
return "DTV_PER"; | |
else if(cmd == DTV_QUALITY) | |
return "DTV_QUALITY"; | |
else if(cmd == DTV_PRE_BER) | |
return "DTV_PRE_BER"; | |
#endif | |
else | |
return "ERROR?"; | |
} | |
void getCNR(int fd) | |
{ | |
dtv_property prop[13]; | |
/**prop[0].cmd = DTV_STAT_CNR; | |
prop[1].cmd = DTV_STAT_SIGNAL_STRENGTH; | |
prop[2].cmd = DTV_STAT_ERROR_BLOCK_COUNT;**/ | |
/* | |
* Prepare the status struct - DVBv5.10 parameters should | |
* come first, as they'll be read together. | |
*/ | |
prop[0].cmd = DTV_STAT_SIGNAL_STRENGTH; | |
prop[1].cmd = DTV_STAT_CNR; | |
prop[2].cmd = DTV_STAT_PRE_ERROR_BIT_COUNT; | |
prop[3].cmd = DTV_STAT_PRE_TOTAL_BIT_COUNT; | |
prop[4].cmd = DTV_STAT_POST_ERROR_BIT_COUNT; | |
prop[5].cmd = DTV_STAT_POST_TOTAL_BIT_COUNT; | |
prop[6].cmd = DTV_STAT_ERROR_BLOCK_COUNT; | |
prop[7].cmd = DTV_STAT_TOTAL_BLOCK_COUNT; | |
#if defined DTV_STATUS | |
/* Now, status and the calculated stats */ | |
prop[8].cmd = DTV_STATUS; | |
prop[9].cmd = DTV_BER; | |
prop[10].cmd = DTV_PER; | |
prop[11].cmd = DTV_QUALITY; | |
prop[12].cmd = DTV_PRE_BER; | |
#endif | |
dtv_properties props; | |
props.props = prop; | |
#if defined DTV_STATUS | |
props.num = 13; | |
#else | |
props.num = 8; | |
#endif | |
if (::ioctl(fd, FE_GET_PROPERTY, &props) < 0) | |
{ | |
cout << "error: ioctl failed on " << fd << endl; | |
::close(fd); | |
::exit(4); | |
} | |
for(unsigned int i=0; i<props.num; i++) | |
{ | |
//if(!prop[i].u.st.len) prop[i].u.st.len = 1; //HACK for missing length | |
for(unsigned int j=0; j<prop[i].u.st.len; j++) | |
{ | |
cout << getCMD(prop[i].cmd) << | |
" S: " << prop[i].u.st.stat[j].svalue << | |
" U: " << unsigned(prop[i].u.st.stat[j].uvalue) << | |
" L: " << unsigned(prop[i].u.st.len) << | |
" Scale: " << getScale(prop[i].u.st.stat[j].scale) << endl; | |
} | |
} | |
/** | |
cout << "DTV_STAT_CNR SValue: " << prop[0].u.st.stat[0].svalue << " UValue:" | |
<< prop[0].u.st.stat[0].uvalue << " Scale: " << getScale(prop[0].u.st.stat[0].scale) << endl; | |
cout << "DTV_STAT_SIGNAL_STRENGTH SValue: " << prop[1].u.st.stat[0].svalue << " UValue:" | |
<< prop[1].u.st.stat[0].uvalue << " Scale: " << getScale(prop[1].u.st.stat[0].scale) << endl; | |
cout << "DTV_STAT_ERROR_BLOCK_COUNT SValue: " << prop[2].u.st.stat[0].svalue << " UValue:" | |
<< prop[2].u.st.stat[0].uvalue << " Scale: " << getScale(prop[2].u.st.stat[0].scale) << endl; | |
**/ | |
} | |
int check_frontend (int frontend_fd) | |
{ | |
fe_status_t status; | |
unsigned int ber; | |
unsigned int ber_scale; | |
float snr; | |
unsigned int snr_scale; | |
float lvl; | |
unsigned int lvl_scale; | |
if (ioctl(frontend_fd, FE_READ_STATUS, &status) == -1) { | |
perror("FE_READ_STATUS failed"); | |
} | |
struct dtv_property p[3]; | |
p[0].cmd = DTV_STAT_SIGNAL_STRENGTH; | |
p[1].cmd = DTV_STAT_CNR; | |
p[2].cmd = DTV_STAT_POST_ERROR_BIT_COUNT; | |
struct dtv_properties p_status; | |
p_status.num = 3; | |
p_status.props = p; | |
if (ioctl(frontend_fd, FE_GET_PROPERTY, &p_status) == -1) { | |
perror("FE_GET_PROPERTY failed"); | |
return -1; | |
} | |
lvl_scale = p_status.props[0].u.st.stat[0].scale; | |
if (lvl_scale == FE_SCALE_DECIBEL) { | |
lvl = p_status.props[0].u.st.stat[0].svalue * 0.0001; | |
} else { | |
int lvl; | |
if (ioctl(frontend_fd, FE_READ_SIGNAL_STRENGTH, &lvl) == -1) { | |
lvl = 0; | |
} else { | |
lvl = (lvl * 100) / 0xffff; | |
if (lvl < 0) { | |
lvl = 0; | |
} | |
} | |
} | |
snr_scale = p_status.props[1].u.st.stat[0].scale; | |
if (snr_scale == FE_SCALE_DECIBEL) { | |
snr = p_status.props[1].u.st.stat[0].svalue * .0001; | |
} else { | |
unsigned int snr = 0; | |
if (ioctl(frontend_fd, FE_READ_SNR, &snr) == -1) { | |
snr = 0; | |
} | |
} | |
ber_scale = p_status.props[2].u.st.stat[0].scale; | |
if (ber_scale == FE_SCALE_COUNTER) { | |
ber = p_status.props[2].u.st.stat[0].uvalue; | |
} else { | |
ber = 0; | |
if (ioctl(frontend_fd, FE_READ_BER, &ber) == -1) { | |
ber = 0; | |
} | |
} | |
printf ("status %s | signal %2.1f dBm | snr %2.1f dB | ber %u | ", | |
(status & FE_HAS_LOCK) ? "Locked" : "Unlocked", lvl, snr, ber); | |
if (status & FE_HAS_LOCK) { | |
printf("FE_HAS_LOCK \n"); | |
} else printf("\n"); | |
return 0; | |
} | |
int main(int argc, char *argv[]) | |
{ | |
int fd = -1; | |
if(argc != 2) | |
{ | |
cout << "usage: " << argv[0] << " <frontend>" << endl; | |
cout << "example: " << argv[0] << " /dev/dvb/adapter0/frontend0" << endl; | |
return 1; | |
} | |
if(::access(argv[1], F_OK) < 0) | |
{ | |
cout << "error: " << argv[1] << " does not exist!" << endl; | |
return 2; | |
} | |
fd = ::open(argv[1], O_RDONLY); //O_RDONLY O_RDWR | |
if(fd < 0) | |
{ | |
cout << "error: " << argv[1] << " failed to open!" << endl; | |
return 3; | |
} | |
while(true) | |
{ | |
getCNR(fd); | |
//check_frontend(fd); | |
usleep(5000000); | |
} | |
::close(fd); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment