00001
00002
00003
00004 #include <pthread.h>
00005 #include <fcntl.h>
00006 #include <unistd.h>
00007 #include <sys/select.h>
00008
00009 #include "mythcontext.h"
00010 #include "mythdbcon.h"
00011 #include "atscstreamdata.h"
00012 #include "mpegtables.h"
00013 #include "atsctables.h"
00014 #include "firewirechannel.h"
00015 #include "firewiresignalmonitor.h"
00016
00017 #define LOC QString("FireSM(%1): ").arg(channel->GetDevice())
00018 #define LOC_WARN QString("FireSM(%1), Warning: ").arg(channel->GetDevice())
00019 #define LOC_ERR QString("FireSM(%1), Error: ").arg(channel->GetDevice())
00020
00021 const uint FirewireSignalMonitor::kPowerTimeout = 3000;
00022 const uint FirewireSignalMonitor::kBufferTimeout = 5000;
00023
00024 QMap<void*,uint> FirewireSignalMonitor::pat_keys;
00025 QMutex FirewireSignalMonitor::pat_keys_lock;
00026
00042 FirewireSignalMonitor::FirewireSignalMonitor(
00043 int db_cardnum,
00044 FirewireChannel *_channel,
00045 uint64_t _flags, const char *_name) :
00046 DTVSignalMonitor(db_cardnum, _channel, _flags, _name),
00047 dtvMonitorRunning(false),
00048 stb_needs_retune(true),
00049 stb_needs_to_wait_for_pat(false),
00050 stb_needs_to_wait_for_power(false)
00051 {
00052 VERBOSE(VB_CHANNEL, LOC + "ctor");
00053
00054 signalStrength.SetThreshold(65);
00055
00056 AddFlags(kDTVSigMon_WaitForSig);
00057
00058 stb_needs_retune =
00059 (FirewireDevice::kAVCPowerOff == _channel->GetPowerState());
00060 }
00061
00065 FirewireSignalMonitor::~FirewireSignalMonitor()
00066 {
00067 VERBOSE(VB_CHANNEL, LOC + "dtor");
00068 Stop();
00069 }
00070
00071 void FirewireSignalMonitor::deleteLater(void)
00072 {
00073 disconnect();
00074 Stop();
00075 DTVSignalMonitor::deleteLater();
00076 }
00077
00081 void FirewireSignalMonitor::Stop(void)
00082 {
00083 VERBOSE(VB_CHANNEL, LOC + "Stop() -- begin");
00084 SignalMonitor::Stop();
00085 if (dtvMonitorRunning)
00086 {
00087 dtvMonitorRunning = false;
00088 pthread_join(table_monitor_thread, NULL);
00089 }
00090 VERBOSE(VB_CHANNEL, LOC + "Stop() -- end");
00091 }
00092
00093 void FirewireSignalMonitor::HandlePAT(const ProgramAssociationTable *pat)
00094 {
00095 AddFlags(kDTVSigMon_PATSeen);
00096
00097 FirewireChannel *fwchan = dynamic_cast<FirewireChannel*>(channel);
00098 bool crc_bogus = !fwchan->GetFirewireDevice()->IsSTBBufferCleared();
00099 if (crc_bogus && stb_needs_to_wait_for_pat &&
00100 (stb_wait_for_pat_timer.elapsed() < (int)kBufferTimeout))
00101 {
00102 VERBOSE(VB_CHANNEL, LOC + "HandlePAT() ignoring PAT");
00103 uint tsid = pat->TransportStreamID();
00104 GetStreamData()->SetVersionPAT(tsid, -1,0);
00105 return;
00106 }
00107
00108 if (crc_bogus && stb_needs_to_wait_for_pat)
00109 {
00110 VERBOSE(VB_IMPORTANT, LOC_WARN + "Wait for valid PAT timed out");
00111 stb_needs_to_wait_for_pat = false;
00112 }
00113
00114 DTVSignalMonitor::HandlePAT(pat);
00115 }
00116
00117 void FirewireSignalMonitor::HandlePMT(uint pnum, const ProgramMapTable *pmt)
00118 {
00119 VERBOSE(VB_CHANNEL, LOC + "HandlePMT()");
00120
00121 AddFlags(kDTVSigMon_PMTSeen);
00122
00123 if (!HasFlags(kDTVSigMon_PATMatch))
00124 {
00125 GetStreamData()->SetVersionPMT(pnum, -1,0);
00126 VERBOSE(VB_CHANNEL, LOC + "HandlePMT() ignoring PMT");
00127 return;
00128 }
00129
00130 DTVSignalMonitor::HandlePMT(pnum, pmt);
00131 }
00132
00133 void *FirewireSignalMonitor::TableMonitorThread(void *param)
00134 {
00135 FirewireSignalMonitor *mon = (FirewireSignalMonitor*) param;
00136 mon->RunTableMonitor();
00137 return NULL;
00138 }
00139
00140 void FirewireSignalMonitor::RunTableMonitor(void)
00141 {
00142 stb_needs_to_wait_for_pat = true;
00143 stb_wait_for_pat_timer.start();
00144 dtvMonitorRunning = true;
00145
00146 VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- begin");
00147
00148 FirewireChannel *lchan = dynamic_cast<FirewireChannel*>(channel);
00149 if (!lchan)
00150 {
00151 VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- err end");
00152 dtvMonitorRunning = false;
00153 return;
00154 }
00155
00156 FirewireDevice *dev = lchan->GetFirewireDevice();
00157
00158 dev->OpenPort();
00159 dev->AddListener(this);
00160
00161 while (dtvMonitorRunning && GetStreamData())
00162 usleep(100000);
00163
00164 VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- shutdown ");
00165
00166 dev->RemoveListener(this);
00167 dev->ClosePort();
00168
00169 dtvMonitorRunning = false;
00170
00171 VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- end");
00172 }
00173
00174 void FirewireSignalMonitor::AddData(const unsigned char *data, uint len)
00175 {
00176 if (!dtvMonitorRunning)
00177 return;
00178
00179 if (GetStreamData())
00180 GetStreamData()->ProcessData((unsigned char *)data, len);
00181 }
00182
00193 void FirewireSignalMonitor::UpdateValues(void)
00194 {
00195 if (!running || exit)
00196 return;
00197
00198 if (dtvMonitorRunning)
00199 {
00200 EmitFirewireSignals();
00201 if (IsAllGood())
00202 emit AllGood();
00203
00204
00205 update_done = true;
00206 return;
00207 }
00208
00209 if (stb_needs_to_wait_for_power &&
00210 (stb_wait_for_power_timer.elapsed() < (int)kPowerTimeout))
00211 {
00212 return;
00213 }
00214 stb_needs_to_wait_for_power = false;
00215
00216 FirewireChannel *fwchan = dynamic_cast<FirewireChannel*>(channel);
00217
00218 if (HasFlags(kFWSigMon_WaitForPower) && !HasFlags(kFWSigMon_PowerMatch))
00219 {
00220 bool retried = false;
00221 while (true)
00222 {
00223 FirewireDevice::PowerState power = fwchan->GetPowerState();
00224 if (FirewireDevice::kAVCPowerOn == power)
00225 {
00226 AddFlags(kFWSigMon_PowerSeen | kFWSigMon_PowerMatch);
00227 }
00228 else if (FirewireDevice::kAVCPowerOff == power)
00229 {
00230 AddFlags(kFWSigMon_PowerSeen);
00231 fwchan->SetPowerState(true);
00232 stb_wait_for_power_timer.start();
00233 stb_needs_to_wait_for_power = true;
00234 }
00235 else
00236 {
00237 bool qfailed = (FirewireDevice::kAVCPowerQueryFailed == power);
00238 if (qfailed && !retried)
00239 {
00240 retried = true;
00241 continue;
00242 }
00243
00244 VERBOSE(VB_RECORD, "Can't determine if STB is power on, "
00245 "assuming it is...");
00246 AddFlags(kFWSigMon_PowerSeen | kFWSigMon_PowerMatch);
00247 }
00248 break;
00249 }
00250 }
00251
00252 bool isLocked = !HasFlags(kFWSigMon_WaitForPower) ||
00253 HasFlags(kFWSigMon_WaitForPower | kFWSigMon_PowerMatch);
00254
00255 if (isLocked && stb_needs_retune)
00256 {
00257 fwchan->Retune();
00258 isLocked = stb_needs_retune = false;
00259 }
00260
00261
00262 {
00263 QMutexLocker locker(&statusLock);
00264 signalStrength.SetValue(isLocked ? 100 : 0);
00265 signalLock.SetValue(isLocked ? 1 : 0);
00266 }
00267
00268 EmitFirewireSignals();
00269 if (IsAllGood())
00270 emit AllGood();
00271
00272
00273
00274 if (isLocked && GetStreamData() &&
00275 HasAnyFlag(kDTVSigMon_WaitForPAT | kDTVSigMon_WaitForPMT |
00276 kDTVSigMon_WaitForMGT | kDTVSigMon_WaitForVCT |
00277 kDTVSigMon_WaitForNIT | kDTVSigMon_WaitForSDT))
00278 {
00279 pthread_create(&table_monitor_thread, NULL,
00280 TableMonitorThread, this);
00281
00282 VERBOSE(VB_CHANNEL, LOC + "UpdateValues() -- "
00283 "Waiting for table monitor to start");
00284
00285 while (!dtvMonitorRunning)
00286 usleep(50);
00287
00288 VERBOSE(VB_CHANNEL, LOC + "UpdateValues() -- "
00289 "Table monitor started");
00290 }
00291
00292 update_done = true;
00293 }
00294
00295 #define EMIT(SIGNAL_FUNC, SIGNAL_VAL) \
00296 do { statusLock.lock(); \
00297 SignalMonitorValue val = SIGNAL_VAL; \
00298 statusLock.unlock(); \
00299 emit SIGNAL_FUNC(val); } while (false)
00300
00304 void FirewireSignalMonitor::EmitFirewireSignals(void)
00305 {
00306
00307 EMIT(StatusSignalLock, signalLock);
00308 if (HasFlags(kDTVSigMon_WaitForSig))
00309 EMIT(StatusSignalStrength, signalStrength);
00310 }
00311
00312 #undef EMIT