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