00001
00007
00008 #include <algorithm>
00009
00010
00011 #include <QMap>
00012
00013
00014 #include "linuxfirewiredevice.h"
00015 #if USING_OSX_FIREWIRE
00016 #include "darwinfirewiredevice.h"
00017 #endif
00018 #include "mythlogging.h"
00019 #include "pespacket.h"
00020
00021 #define LOC QString("FireDev(%1): ").arg(guid_to_string(m_guid))
00022
00023 static void fw_init(QMap<uint64_t,QString> &id_to_model);
00024
00025 QMap<uint64_t,QString> FirewireDevice::s_id_to_model;
00026 QMutex FirewireDevice::s_static_lock;
00027
00028 FirewireDevice::FirewireDevice(uint64_t guid, uint subunitid, uint speed) :
00029 m_guid(guid), m_subunitid(subunitid),
00030 m_speed(speed),
00031 m_last_channel(0), m_last_crc(0),
00032 m_buffer_cleared(true), m_open_port_cnt(0),
00033 m_lock()
00034 {
00035 }
00036
00037 void FirewireDevice::AddListener(TSDataListener *listener)
00038 {
00039 if (listener)
00040 {
00041 vector<TSDataListener*>::iterator it =
00042 find(m_listeners.begin(), m_listeners.end(), listener);
00043
00044 if (it == m_listeners.end())
00045 m_listeners.push_back(listener);
00046 }
00047
00048 LOG(VB_RECORD, LOG_INFO, LOC +
00049 QString("AddListener() %1").arg(m_listeners.size()));
00050 }
00051
00052 void FirewireDevice::RemoveListener(TSDataListener *listener)
00053 {
00054 vector<TSDataListener*>::iterator it = m_listeners.end();
00055
00056 do
00057 {
00058 it = find(m_listeners.begin(), m_listeners.end(), listener);
00059 if (it != m_listeners.end())
00060 {
00061 m_listeners.erase(it);
00062 it = m_listeners.begin();
00063 }
00064 }
00065 while (it != m_listeners.end());
00066
00067 LOG(VB_RECORD, LOG_INFO, LOC +
00068 QString("RemoveListener() %1").arg(m_listeners.size()));
00069 }
00070
00071 bool FirewireDevice::SetPowerState(bool on)
00072 {
00073 QMutexLocker locker(&m_lock);
00074
00075 vector<uint8_t> cmd;
00076 vector<uint8_t> ret;
00077
00078 cmd.push_back(kAVCControlCommand);
00079 cmd.push_back(kAVCSubunitTypeUnit | kAVCSubunitIdIgnore);
00080 cmd.push_back(kAVCUnitPowerOpcode);
00081 cmd.push_back((on) ? kAVCPowerStateOn : kAVCPowerStateOff);
00082
00083 QString cmdStr = (on) ? "on" : "off";
00084 LOG(VB_RECORD, LOG_INFO, LOC + QString("Powering %1").arg(cmdStr));
00085
00086 if (!SendAVCCommand(cmd, ret, -1))
00087 {
00088 LOG(VB_GENERAL, LOG_ERR, LOC + "Power on cmd failed (no response)");
00089 return false;
00090 }
00091
00092 if (kAVCAcceptedStatus != ret[0])
00093 {
00094 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Power %1 failed").arg(cmdStr));
00095
00096 return false;
00097 }
00098
00099 LOG(VB_RECORD, LOG_INFO, LOC +
00100 QString("Power %1 cmd sent successfully").arg(cmdStr));
00101
00102 return true;
00103 }
00104
00105 FirewireDevice::PowerState FirewireDevice::GetPowerState(void)
00106 {
00107 QMutexLocker locker(&m_lock);
00108
00109 vector<uint8_t> cmd;
00110 vector<uint8_t> ret;
00111
00112 cmd.push_back(kAVCStatusInquiryCommand);
00113 cmd.push_back(kAVCSubunitTypeUnit | kAVCSubunitIdIgnore);
00114 cmd.push_back(kAVCUnitPowerOpcode);
00115 cmd.push_back(kAVCPowerStateQuery);
00116
00117 LOG(VB_CHANNEL, LOG_INFO, LOC + "Requesting STB Power State");
00118
00119 if (!SendAVCCommand(cmd, ret, -1))
00120 {
00121 LOG(VB_GENERAL, LOG_ERR, LOC + "Power cmd failed (no response)");
00122 return kAVCPowerQueryFailed;
00123 }
00124
00125 QString loc = LOC + "STB Power State: ";
00126
00127 if (ret[0] != kAVCResponseImplemented)
00128 {
00129 LOG(VB_CHANNEL, LOG_INFO, loc + "Query not implemented");
00130 return kAVCPowerUnknown;
00131 }
00132
00133
00134 if (ret[3] == kAVCPowerStateOn)
00135 {
00136 LOG(VB_CHANNEL, LOG_INFO, loc + "On");
00137 return kAVCPowerOn;
00138 }
00139
00140 if (ret[3] == kAVCPowerStateOff)
00141 {
00142 LOG(VB_CHANNEL, LOG_INFO, loc + "Off");
00143 return kAVCPowerOff;
00144 }
00145
00146 LOG(VB_GENERAL, LOG_ERR, LOC + "STB Power State: Unknown Response");
00147
00148 return kAVCPowerUnknown;
00149 }
00150
00151 bool FirewireDevice::SetChannel(const QString &panel_model,
00152 uint alt_method, uint channel)
00153 {
00154 LOG(VB_CHANNEL, LOG_INFO, QString("SetChannel(model %1, alt %2, chan %3)")
00155 .arg(panel_model).arg(alt_method).arg(channel));
00156
00157 QMutexLocker locker(&m_lock);
00158 LOG(VB_CHANNEL, LOG_INFO, "SetChannel() -- locked");
00159
00160 if (!IsSTBSupported(panel_model))
00161 {
00162 LOG(VB_GENERAL, LOG_ERR, LOC +
00163 QString("Model: '%1' ").arg(panel_model) +
00164 "is not supported by internal channel changer.");
00165 return false;
00166 }
00167
00168 int digit[3];
00169 digit[0] = (channel % 1000) / 100;
00170 digit[1] = (channel % 100) / 10;
00171 digit[2] = (channel % 10);
00172
00173 if (m_subunitid >= kAVCSubunitIdExtended)
00174 {
00175 LOG(VB_GENERAL, LOG_ERR, LOC +
00176 "SetChannel: Extended subunits are not supported.");
00177
00178 return false;
00179 }
00180
00181 vector<uint8_t> cmd;
00182 vector<uint8_t> ret;
00183
00184 if ((panel_model.toUpper() == "SA GENERIC") ||
00185 (panel_model.toUpper() == "SA4200HD") ||
00186 (panel_model.toUpper() == "SA4250HDC"))
00187 {
00188 if (panel_model.toUpper() == "SA4250HDC")
00189 {
00190 LOG(VB_GENERAL, LOG_ERR, LOC +
00191 "The Scientific Atlanta 4250 HDC is not supported "
00192 "\n\t\t\tby any MythTV Firewire channel changer."
00193 "At the moment you must use an IR blaster.");
00194 }
00195
00196 cmd.push_back(kAVCControlCommand);
00197 cmd.push_back(kAVCSubunitTypePanel | m_subunitid);
00198 cmd.push_back(kAVCPanelPassThrough);
00199 cmd.push_back(kAVCPanelKeyTuneFunction | kAVCPanelKeyPress);
00200
00201 cmd.push_back(4);
00202 cmd.push_back((channel>>8) & 0x0f);
00203 cmd.push_back(channel & 0xff);
00204 cmd.push_back(0x00);
00205 cmd.push_back(0x00);
00206
00207 if (!SendAVCCommand(cmd, ret, -1))
00208 return false;
00209
00210 bool press_ok = (kAVCAcceptedStatus == ret[0]);
00211
00212 cmd[3]= kAVCPanelKeyTuneFunction | kAVCPanelKeyRelease;
00213 if (!SendAVCCommand(cmd, ret, -1))
00214 return false;
00215
00216 bool release_ok = (kAVCAcceptedStatus == ret[0]);
00217
00218 if (!press_ok && !release_ok)
00219 {
00220 LOG(VB_GENERAL, LOG_ERR, LOC + "Tuning failed");
00221 return false;
00222 }
00223
00224 SetLastChannel(channel);
00225 return true;
00226 }
00227
00228
00229
00230 bool is_mot = ((panel_model.toUpper().left(4) == "DCT-") ||
00231 (panel_model.toUpper().left(4) == "DCH-") ||
00232 (panel_model.toUpper().left(4) == "DCX-") ||
00233 (panel_model.toUpper().left(4) == "QIP-") ||
00234 (panel_model.toUpper().left(4) == "MOTO") ||
00235 (panel_model.toUpper().left(5) == "PACE-"));
00236
00237 if (is_mot && !alt_method)
00238 {
00239 for (uint i = 0; i < 3 ;i++)
00240 {
00241 cmd.clear();
00242 cmd.push_back(kAVCControlCommand);
00243 cmd.push_back(kAVCSubunitTypePanel | m_subunitid);
00244 cmd.push_back(kAVCPanelPassThrough);
00245 cmd.push_back((kAVCPanelKey0 + digit[i]) | kAVCPanelKeyPress);
00246 cmd.push_back(0x00);
00247 cmd.push_back(0x00);
00248 cmd.push_back(0x00);
00249 cmd.push_back(0x00);
00250
00251 if (!SendAVCCommand(cmd, ret, -1))
00252 return false;
00253
00254 usleep(500000);
00255 }
00256
00257 SetLastChannel(channel);
00258 return true;
00259 }
00260
00261 if (is_mot && alt_method)
00262 {
00263 cmd.push_back(kAVCControlCommand);
00264 cmd.push_back(kAVCSubunitTypePanel | m_subunitid);
00265 cmd.push_back(kAVCPanelPassThrough);
00266 cmd.push_back(kAVCPanelKeyTuneFunction | kAVCPanelKeyPress);
00267
00268 cmd.push_back(4);
00269 cmd.push_back((channel>>8) & 0x0f);
00270 cmd.push_back(channel & 0xff);
00271 cmd.push_back(0x00);
00272 cmd.push_back(0xff);
00273
00274 if (!SendAVCCommand(cmd, ret, -1))
00275 return false;
00276
00277 SetLastChannel(channel);
00278 return true;
00279 }
00280
00281 if (panel_model.toUpper() == "SA3250HD")
00282 {
00283 cmd.push_back(kAVCControlCommand);
00284 cmd.push_back(kAVCSubunitTypePanel | m_subunitid);
00285 cmd.push_back(kAVCPanelPassThrough);
00286 cmd.push_back(kAVCPanelKeyTuneFunction | kAVCPanelKeyRelease);
00287
00288 cmd.push_back(4);
00289 cmd.push_back(0x30 | digit[2]);
00290 cmd.push_back(0x30 | digit[1]);
00291 cmd.push_back(0x30 | digit[0]);
00292 cmd.push_back(0xff);
00293
00294 if (!SendAVCCommand(cmd, ret, -1))
00295 return false;
00296
00297 cmd[5] = 0x30 | digit[0];
00298 cmd[6] = 0x30 | digit[1];
00299 cmd[7] = 0x30 | digit[2];
00300
00301 if (!SendAVCCommand(cmd, ret, -1))
00302 return false;
00303
00304 SetLastChannel(channel);
00305 return true;
00306 }
00307
00308 return false;
00309 }
00310
00311 void FirewireDevice::BroadcastToListeners(
00312 const unsigned char *data, uint dataSize)
00313 {
00314 if ((dataSize >= TSPacket::kSize) && (data[0] == SYNC_BYTE) &&
00315 ((data[1] & 0x1f) == 0) && (data[2] == 0))
00316 {
00317 ProcessPATPacket(*((const TSPacket*)data));
00318 }
00319
00320 vector<TSDataListener*>::iterator it = m_listeners.begin();
00321 for (; it != m_listeners.end(); ++it)
00322 (*it)->AddData(data, dataSize);
00323 }
00324
00325 void FirewireDevice::SetLastChannel(const uint channel)
00326 {
00327 m_buffer_cleared = (channel == m_last_channel);
00328 m_last_channel = channel;
00329
00330 LOG(VB_GENERAL, LOG_INFO, QString("SetLastChannel(%1): cleared: %2")
00331 .arg(channel).arg(m_buffer_cleared ? "yes" : "no"));
00332 }
00333
00334 void FirewireDevice::ProcessPATPacket(const TSPacket &tspacket)
00335 {
00336 if (!tspacket.TransportError() && !tspacket.Scrambled() &&
00337 tspacket.HasPayload() && tspacket.PayloadStart() && !tspacket.PID())
00338 {
00339 PESPacket pes = PESPacket::View(tspacket);
00340 uint crc = pes.CalcCRC();
00341 m_buffer_cleared |= (crc != m_last_crc);
00342 m_last_crc = crc;
00343 #if 0
00344 LOG(VB_RECORD, LOG_DEBUG, LOC +
00345 QString("ProcessPATPacket: CRC 0x%1 cleared: %2")
00346 .arg(crc,0,16).arg(m_buffer_cleared ? "yes" : "no"));
00347 #endif
00348 }
00349 else
00350 {
00351 LOG(VB_GENERAL, LOG_ERR, LOC + "Can't handle large PAT's");
00352 }
00353 }
00354
00355 QString FirewireDevice::GetModelName(uint vendor_id, uint model_id)
00356 {
00357 QMutexLocker locker(&s_static_lock);
00358 if (s_id_to_model.empty())
00359 fw_init(s_id_to_model);
00360
00361 QString ret = s_id_to_model[(((uint64_t) vendor_id) << 32) | model_id];
00362
00363 if (ret.isEmpty())
00364 return "MOTO GENERIC";
00365
00366 ret.detach();
00367 return ret;
00368 }
00369
00370 vector<AVCInfo> FirewireDevice::GetSTBList(void)
00371 {
00372 vector<AVCInfo> list;
00373
00374 #ifdef USING_LINUX_FIREWIRE
00375 list = LinuxFirewireDevice::GetSTBList();
00376 #elif USING_OSX_FIREWIRE
00377 list = DarwinFirewireDevice::GetSTBList();
00378 #endif
00379
00380
00381 #ifdef DEBUG_AVC_INFO
00382 AVCInfo info;
00383 info.guid = 0x0016928a7b600001ULL;
00384 info.specid = 0x0;
00385 info.vendorid = 0x000014f8;
00386 info.modelid = 0x00001072;
00387 info.firmware_revision = 0x0;
00388 info.product_name = "Explorer 4200 HD";
00389 list.push_back(info);
00390
00391 info.guid = 0xff2145a850e39810ULL;
00392 info.specid = 0x0;
00393 info.vendorid = 0x000014f8;
00394 info.modelid = 0x00000be0;
00395 info.firmware_revision = 0x0;
00396 info.product_name = "Explorer 3250 HD";
00397 list.push_back(info);
00398 #endif // DEBUG_AVC_INFO
00399
00400 return list;
00401 }
00402
00403 static void fw_init(QMap<uint64_t,QString> &id_to_model)
00404 {
00405 const uint64_t sa_vendor_ids[] =
00406 {
00407 0x0a73, 0x0f21, 0x11e6, 0x14f8, 0x1692, 0x1868,
00408 0x1947, 0x1ac3, 0x1bd7, 0x1cea, 0x1e6b, 0x21be,
00409 0x223a, 0x22ce, 0x23be, 0x252e,
00410 };
00411 const uint sa_vendor_id_cnt =
00412 sizeof(sa_vendor_ids) / sizeof(uint64_t);
00413
00414 for (uint i = 0; i < sa_vendor_id_cnt; i++)
00415 {
00416 id_to_model[sa_vendor_ids[i] << 32 | 0x0be0] = "SA3250HD";
00417 id_to_model[sa_vendor_ids[i] << 32 | 0x1072] = "SA4200HD";
00418 id_to_model[sa_vendor_ids[i] << 32 | 0x10cc] = "SA4250HDC";
00419 id_to_model[sa_vendor_ids[i] << 32 | 0x22ce] = "SA8300HD";
00420 }
00421
00422 const uint64_t motorola_vendor_ids[] =
00423 {
00424
00425 0x1c11, 0x1cfb, 0x1fc4, 0x23a3, 0x23ee, 0x25f1,
00426 0xfa01, 0x25f1, 0x25f2, 0xcc7d37,
00427
00428 0x24a0,
00429
00430 0x1e46,
00431
00432 0x1bdd,
00433
00434 0x159a,
00435
00436 0x0ce5, 0x0e5c, 0x1225, 0x0f9f, 0x1180,
00437 0x12c9, 0x11ae, 0x152f, 0x14e8, 0x16b5, 0x1371,
00438 0x19a6, 0x1aad, 0x0b06, 0x195e, 0x10dc,
00439
00440 0x0f9f, 0x152f,
00441
00442 0x17ee, 0x1a66,
00443
00444 0x211e,
00445
00446 0x2374,
00447
00448 0x04db, 0x0406, 0x0ce5, 0x111a, 0x1225, 0x1404,
00449 0x1626, 0x18c0, 0x1ade, 0x1cfb, 0x2040, 0x2180,
00450 0x2210, 0x230b, 0x2375, 0x2395, 0x23a2, 0x23ed,
00451 0x23ee, 0x23a0, 0x23a1,
00452
00453 };
00454 const uint motorola_vendor_id_cnt =
00455 sizeof(motorola_vendor_ids) / sizeof(uint64_t);
00456
00457 for (uint i = 0; i < motorola_vendor_id_cnt; i++)
00458 {
00459 id_to_model[motorola_vendor_ids[i] << 32 | 0xf740] = "DCX-3200";
00460 id_to_model[motorola_vendor_ids[i] << 32 | 0xf804] = "DCX-3200";
00461 id_to_model[motorola_vendor_ids[i] << 32 | 0xfa03] = "DCX-3200";
00462 id_to_model[motorola_vendor_ids[i] << 32 | 0xfa05] = "DCX-3200";
00463 id_to_model[motorola_vendor_ids[i] << 32 | 0xfa07] = "DCX-3200";
00464 id_to_model[motorola_vendor_ids[i] << 32 | 0x24a1] = "DCX-3200";
00465 id_to_model[motorola_vendor_ids[i] << 32 | 0xea05] = "DCX-3432";
00466 id_to_model[motorola_vendor_ids[i] << 32 | 0xd330] = "DCH-3200";
00467 id_to_model[motorola_vendor_ids[i] << 32 | 0xb630] = "DCH-3416";
00468 id_to_model[motorola_vendor_ids[i] << 32 | 0x34cb] = "DCT-3412";
00469 id_to_model[motorola_vendor_ids[i] << 32 | 0x346b] = "DCT-3416";
00470 id_to_model[motorola_vendor_ids[i] << 32 | 0xb630] = "DCT-3416";
00471 id_to_model[motorola_vendor_ids[i] << 32 | 0x6200] = "DCT-6200";
00472 id_to_model[motorola_vendor_ids[i] << 32 | 0x620a] = "DCT-6200";
00473 id_to_model[motorola_vendor_ids[i] << 32 | 0x64ca] = "DCT-6212";
00474 id_to_model[motorola_vendor_ids[i] << 32 | 0x64cb] = "DCT-6212";
00475 id_to_model[motorola_vendor_ids[i] << 32 | 0x646b] = "DCT-6216";
00476 id_to_model[motorola_vendor_ids[i] << 32 | 0x8100] = "QIP-7100";
00477 id_to_model[motorola_vendor_ids[i] << 32 | 0x7100] = "QIP-6200";
00478 id_to_model[motorola_vendor_ids[i] << 32 | 0x0001] = "QIP-7100";
00479 }
00480
00481 const uint64_t pace_vendor_ids[] =
00482 {
00483
00484 0x1cc3, 0x5094,
00485 };
00486
00487 const uint pace_vendor_id_cnt =
00488 sizeof(pace_vendor_ids) / sizeof(uint64_t);
00489
00490 for (uint i = 0; i < pace_vendor_id_cnt; i++)
00491 {
00492 id_to_model[pace_vendor_ids[i] << 32 | 0x10551] = "PACE-550";
00493 id_to_model[pace_vendor_ids[i] << 32 | 0x10755] = "PACE-779";
00494 }
00495 }
00496
00497 bool FirewireDevice::IsSTBSupported(const QString &panel_model)
00498 {
00499 QString model = panel_model.toUpper();
00500 return ((model == "DCH-3200") ||
00501 (model == "DCH-3416") ||
00502 (model == "DCT-3412") ||
00503 (model == "DCT-3416") ||
00504 (model == "DCT-6200") ||
00505 (model == "DCT-6212") ||
00506 (model == "DCT-6216") ||
00507 (model == "SA3250HD") ||
00508 (model == "SA4200HD") ||
00509 (model == "SA4250HDC") ||
00510 (model == "SA8300HD") ||
00511 (model == "PACE-550") ||
00512 (model == "PACE-779") ||
00513 (model == "QIP-6200") ||
00514 (model == "QIP-7100") ||
00515 (model == "SA GENERIC") ||
00516 (model == "MOTO GENERIC"));
00517 }
00518