+/*****************************************************************************
+ * FrontendPoll : Poll for frontend events
+ *****************************************************************************/
+void FrontendPoll( access_t *p_access )
+{
+ access_sys_t *p_sys = p_access->p_sys;
+ frontend_t * p_frontend = p_sys->p_frontend;
+ struct dvb_frontend_event event;
+ fe_status_t i_status, i_diff;
+
+ for( ;; )
+ {
+ int i_ret = ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event );
+
+ if( i_ret < 0 )
+ {
+ if( errno == EWOULDBLOCK )
+ return; /* no more events */
+
+ msg_Err( p_access, "reading frontend event failed (%d): %m",
+ i_ret );
+ return;
+ }
+
+ i_status = event.status;
+ i_diff = i_status ^ p_frontend->i_last_status;
+ p_frontend->i_last_status = i_status;
+
+ {
+#define IF_UP( x ) \
+ } \
+ if ( i_diff & (x) ) \
+ { \
+ if ( i_status & (x) )
+
+ IF_UP( FE_HAS_SIGNAL )
+ msg_Dbg( p_access, "frontend has acquired signal" );
+ else
+ msg_Dbg( p_access, "frontend has lost signal" );
+
+ IF_UP( FE_HAS_CARRIER )
+ msg_Dbg( p_access, "frontend has acquired carrier" );
+ else
+ msg_Dbg( p_access, "frontend has lost carrier" );
+
+ IF_UP( FE_HAS_VITERBI )
+ msg_Dbg( p_access, "frontend has acquired stable FEC" );
+ else
+ msg_Dbg( p_access, "frontend has lost FEC" );
+
+ IF_UP( FE_HAS_SYNC )
+ msg_Dbg( p_access, "frontend has acquired sync" );
+ else
+ msg_Dbg( p_access, "frontend has lost sync" );
+
+ IF_UP( FE_HAS_LOCK )
+ {
+ frontend_statistic_t stat;
+
+ msg_Dbg( p_access, "frontend has acquired lock" );
+ p_sys->i_frontend_timeout = 0;
+
+ /* Read some statistics */
+ if( !FrontendGetStatistic( p_access, &stat ) )
+ {
+ if( stat.i_ber >= 0 )
+ msg_Dbg( p_access, "- Bit error rate: %d", stat.i_ber );
+ if( stat.i_signal_strenth >= 0 )
+ msg_Dbg( p_access, "- Signal strength: %d", stat.i_signal_strenth );
+ if( stat.i_snr >= 0 )
+ msg_Dbg( p_access, "- SNR: %d", stat.i_snr );
+ }
+ }
+ else
+ {
+ msg_Dbg( p_access, "frontend has lost lock" );
+ p_sys->i_frontend_timeout = mdate() + FRONTEND_LOCK_TIMEOUT;
+ }
+
+ IF_UP( FE_REINIT )
+ {
+ /* The frontend was reinited. */
+ msg_Warn( p_access, "reiniting frontend");
+ FrontendSet( p_access );
+ }
+ }
+#undef IF_UP
+ }
+}
+int FrontendGetStatistic( access_t *p_access, frontend_statistic_t *p_stat )
+{
+ access_sys_t *p_sys = p_access->p_sys;
+ frontend_t * p_frontend = p_sys->p_frontend;
+
+ if( (p_frontend->i_last_status & FE_HAS_LOCK) == 0 )
+ return VLC_EGENERIC;
+
+ memset( p_stat, 0, sizeof(*p_stat) );
+ if( ioctl( p_sys->i_frontend_handle, FE_READ_BER, &p_stat->i_ber ) < 0 )
+ p_stat->i_ber = -1;
+ if( ioctl( p_sys->i_frontend_handle, FE_READ_SIGNAL_STRENGTH, &p_stat->i_signal_strenth ) < 0 )
+ p_stat->i_signal_strenth = -1;
+ if( ioctl( p_sys->i_frontend_handle, FE_READ_SNR, &p_stat->i_snr ) < 0 )
+ p_stat->i_snr = -1;
+
+ return VLC_SUCCESS;
+}
+void FrontendGetStatus( access_t *p_access, frontend_status_t *p_status )
+{
+ access_sys_t *p_sys = p_access->p_sys;
+ frontend_t * p_frontend = p_sys->p_frontend;
+
+ p_status->b_has_signal = (p_frontend->i_last_status & FE_HAS_SIGNAL) != 0;
+ p_status->b_has_carrier = (p_frontend->i_last_status & FE_HAS_CARRIER) != 0;
+ p_status->b_has_lock = (p_frontend->i_last_status & FE_HAS_LOCK) != 0;
+}
+static int ScanParametersDvbC( access_t *p_access, scan_parameter_t *p_scan )
+{
+ const frontend_t *p_frontend = p_access->p_sys->p_frontend;
+
+
+ memset( p_scan, 0, sizeof(*p_scan) );
+ p_scan->type = SCAN_DVB_C;
+ p_scan->b_exhaustive = false;
+
+ /* */
+ p_scan->frequency.i_min = p_frontend->info.frequency_min;
+ p_scan->frequency.i_max = p_frontend->info.frequency_max;
+ p_scan->frequency.i_step = p_frontend->info.frequency_stepsize
+ ? p_frontend->info.frequency_stepsize : 166667;
+ p_scan->frequency.i_count = (p_scan->frequency.i_max-p_scan->frequency.i_min)/p_scan->frequency.i_step;
+
+ /* */
+ p_scan->bandwidth.i_min = 6;
+ p_scan->bandwidth.i_max = 8;
+ p_scan->bandwidth.i_step = 1;
+ p_scan->bandwidth.i_count = 3;
+ return VLC_SUCCESS;
+}
+static int ScanParametersDvbT( access_t *p_access, scan_parameter_t *p_scan )
+{
+ const frontend_t *p_frontend = p_access->p_sys->p_frontend;
+
+
+ memset( p_scan, 0, sizeof(*p_scan) );
+ p_scan->type = SCAN_DVB_T;
+ p_scan->b_exhaustive = false;
+
+ /* */
+ p_scan->frequency.i_min = p_frontend->info.frequency_min;
+ p_scan->frequency.i_max = p_frontend->info.frequency_max;
+ p_scan->frequency.i_step = p_frontend->info.frequency_stepsize
+ ? p_frontend->info.frequency_stepsize : 166667;
+ p_scan->frequency.i_count = (p_scan->frequency.i_max-p_scan->frequency.i_min)/p_scan->frequency.i_step;
+
+ /* */
+ p_scan->bandwidth.i_min = 6;
+ p_scan->bandwidth.i_max = 8;
+ p_scan->bandwidth.i_step = 1;
+ p_scan->bandwidth.i_count = 3;
+ return VLC_SUCCESS;
+}
+int FrontendGetScanParameter( access_t *p_access, scan_parameter_t *p_scan )
+{
+ access_sys_t *p_sys = p_access->p_sys;
+ const frontend_t *p_frontend = p_sys->p_frontend;
+
+ if( p_frontend->info.type == FE_OFDM ) // DVB-T
+ return ScanParametersDvbT( p_access, p_scan );
+ else if( p_frontend->info.type == FE_QAM ) // DVB-C
+ return ScanParametersDvbC( p_access, p_scan );
+
+ msg_Err( p_access, "Frontend type not supported for scanning" );
+ return VLC_EGENERIC;
+}
+
+#ifdef ENABLE_HTTPD
+/*****************************************************************************
+ * FrontendStatus : Read frontend status
+ *****************************************************************************/
+void FrontendStatus( access_t *p_access )
+{
+ access_sys_t *p_sys = p_access->p_sys;
+ frontend_t *p_frontend = p_sys->p_frontend;
+ char *p = p_sys->psz_frontend_info = malloc( 10000 );
+ fe_status_t i_status;
+ int i_ret;
+
+ /* Determine type of frontend */
+ if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_GET_INFO,
+ &p_frontend->info )) < 0 )
+ {
+ char buf[1000];
+ strerror_r( errno, buf, sizeof( buf ) );
+ p += sprintf( p, "ioctl FE_GET_INFO failed (%d) %s\n", i_ret, buf );
+ goto out;
+ }
+
+ /* Print out frontend capabilities. */
+ p += sprintf( p, "<table border=1><tr><th>name</th><td>%s</td></tr>\n",
+ p_frontend->info.name );
+ switch( p_frontend->info.type )
+ {
+ case FE_QPSK:
+ p += sprintf( p, "<tr><th>type</th><td>QPSK (DVB-S)</td></tr>\n" );
+ break;
+ case FE_QAM:
+ p += sprintf( p, "<tr><th>type</th><td>QAM (DVB-C)</td></tr>\n" );
+ break;
+ case FE_OFDM:
+ p += sprintf( p, "<tr><th>type</th><td>OFDM (DVB-T)</td></tr>\n" );
+ break;
+#if 0 /* DVB_API_VERSION == 3 */
+ case FE_MEMORY:
+ p += sprintf( p, "<tr><th>type</th><td>MEMORY</td></tr>\n" );
+ break;
+ case FE_NET:
+ p += sprintf( p, "<tr><th>type</th><td>NETWORK</td></tr>\n" );
+ break;
+#endif
+ default:
+ p += sprintf( p, "<tr><th>type</th><td>UNKNOWN (%d)</td></tr>\n",
+ p_frontend->info.type );
+ goto out;
+ }
+#define CHECK_INFO( x ) \
+ p += sprintf( p, \
+ "<tr><th>" STRINGIFY(x) "</th><td>%u</td></tr>\n", \
+ p_frontend->info.x );
+
+ CHECK_INFO( frequency_min );
+ CHECK_INFO( frequency_max );
+ CHECK_INFO( frequency_stepsize );
+ CHECK_INFO( frequency_tolerance );
+ CHECK_INFO( symbol_rate_min );
+ CHECK_INFO( symbol_rate_max );
+ CHECK_INFO( symbol_rate_tolerance );
+ CHECK_INFO( notifier_delay );
+#undef CHECK_INFO
+
+ p += sprintf( p, "</table><p>Frontend capability list:\n<table border=1>" );
+
+#define CHECK_CAPS( x ) \
+ if ( p_frontend->info.caps & (FE_##x) ) \
+ p += sprintf( p, "<tr><td>" STRINGIFY(x) "</td></tr>\n" );
+
+ CHECK_CAPS( IS_STUPID );
+ CHECK_CAPS( CAN_INVERSION_AUTO );
+ CHECK_CAPS( CAN_FEC_1_2 );
+ CHECK_CAPS( CAN_FEC_2_3 );
+ CHECK_CAPS( CAN_FEC_3_4 );
+ CHECK_CAPS( CAN_FEC_4_5 );
+ CHECK_CAPS( CAN_FEC_5_6 );
+ CHECK_CAPS( CAN_FEC_6_7 );
+ CHECK_CAPS( CAN_FEC_7_8 );
+ CHECK_CAPS( CAN_FEC_8_9 );
+ CHECK_CAPS( CAN_FEC_AUTO );
+ CHECK_CAPS( CAN_QPSK );
+ CHECK_CAPS( CAN_QAM_16 );
+ CHECK_CAPS( CAN_QAM_32 );
+ CHECK_CAPS( CAN_QAM_64 );
+ CHECK_CAPS( CAN_QAM_128 );
+ CHECK_CAPS( CAN_QAM_256 );
+ CHECK_CAPS( CAN_QAM_AUTO );
+ CHECK_CAPS( CAN_TRANSMISSION_MODE_AUTO );
+ CHECK_CAPS( CAN_BANDWIDTH_AUTO );
+ CHECK_CAPS( CAN_GUARD_INTERVAL_AUTO );
+ CHECK_CAPS( CAN_HIERARCHY_AUTO );
+ CHECK_CAPS( CAN_MUTE_TS );
+ CHECK_CAPS( CAN_RECOVER );
+#if 0 /* Disabled because of older distributions */
+ CHECK_CAPS( CAN_CLEAN_SETUP );
+#endif
+#undef CHECK_CAPS
+
+ p += sprintf( p, "</table><p>Current frontend status:\n<table border=1>" );
+
+ if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_READ_STATUS, &i_status ))
+ < 0 )
+ {
+ char buf[1000];
+ strerror_r( errno, buf, sizeof( buf ) );
+ p += sprintf( p, "</table>ioctl FE_READ_STATUS failed (%d) %s\n",
+ i_ret, buf );
+ goto out;
+ }
+
+#define CHECK_STATUS( x ) \
+ if ( i_status & (FE_##x) ) \
+ p += sprintf( p, "<tr><td>" STRINGIFY(x) "</td></tr>\n" );
+
+ CHECK_STATUS( HAS_SIGNAL );
+ CHECK_STATUS( HAS_CARRIER );
+ CHECK_STATUS( HAS_VITERBI );
+ CHECK_STATUS( HAS_SYNC );
+ CHECK_STATUS( HAS_LOCK );
+ CHECK_STATUS( REINIT );
+ if( i_status == 0 )
+ p += sprintf( p, "<tr><td>Tuning failed</td></tr>\n" );
+#undef CHECK_STATUS
+
+ if ( i_status & FE_HAS_LOCK )
+ {
+ int32_t i_value;
+ p += sprintf( p, "</table><p>Signal status:\n<table border=1>" );
+ if( ioctl( p_sys->i_frontend_handle, FE_READ_BER, &i_value ) >= 0 )
+ p += sprintf( p, "<tr><th>Bit error rate</th><td>%d</td></tr>\n",
+ i_value );
+ if( ioctl( p_sys->i_frontend_handle, FE_READ_SIGNAL_STRENGTH,
+ &i_value ) >= 0 )
+ p += sprintf( p, "<tr><th>Signal strength</th><td>%d</td></tr>\n",
+ i_value );
+ if( ioctl( p_sys->i_frontend_handle, FE_READ_SNR, &i_value ) >= 0 )
+ p += sprintf( p, "<tr><th>SNR</th><td>%d</td></tr>\n",
+ i_value );
+ }
+ p += sprintf( p, "</table>" );
+
+out:
+ vlc_mutex_lock( &p_sys->httpd_mutex );
+ p_sys->b_request_frontend_info = false;
+ vlc_cond_signal( &p_sys->httpd_cond );
+ vlc_mutex_unlock( &p_sys->httpd_mutex );
+}
+#endif
+