Ticket #4752: r5000_r1.patch

File r5000_r1.patch, 92.2 KB (added by anonymous, 4 years ago)

MythTV patch rev1

  • configure

    old new  
    158158  echo "  --disable-v4l            disable Video4Linux support" 
    159159  echo "  --disable-ivtv           disable ivtv support (PVR-x50) req. v4l support" 
    160160  echo "  --disable-dvb            disable DVB support" 
     161  echo "  --disable-r5000          disable support for R5000 USB STBs" 
    161162  echo "  --dvb-path=HDRLOC        location of directory containing" 
    162163  echo "                           'linux/dvb/frontend.h', not the" 
    163164  echo "                           directory with frontend.h [$dvb_path]" 
     
    870871    hdhomerun 
    871872    iptv 
    872873    ivtv 
     874    r5000 
    873875    joystick_menu 
    874876    lirc 
    875877    opengl_vsync 
     
    10221024dbox2_deps="backend" 
    10231025dvb_deps="backend" 
    10241026firewire_deps="backend" 
     1027r5000_deps="backend" 
    10251028iptv_deps="backend" 
    10261029ivtv_deps="backend v4l" 
    10271030hdhomerun_deps="backend" 
     
    11531156hdhomerun="yes" 
    11541157iptv="yes" 
    11551158ivtv="yes" 
     1159r5000="yes" 
    11561160joystick_menu="default" 
    11571161lamemp3="yes" 
    11581162lirc="yes" 
     
    29282932  echo "DBox2 support             ${dbox2-no}" 
    29292933  echo "HDHomeRun support         ${hdhomerun-no}" 
    29302934  echo "IPTV support              ${iptv-no}" 
     2935  echo "R5000 support             ${r5000-no}" 
    29312936fi 
    29322937 
    29332938if enabled frontend; then 
  • libs/libmythtv/cardutil.h

    old new  
    5353        FIREWIRE, 
    5454        HDHOMERUN, 
    5555        FREEBOX, 
     56        R5000, 
    5657    }; 
    5758 
    5859    static enum CARD_TYPES toCardType(const QString &name) 
     
    8182            return HDHOMERUN; 
    8283        if ("FREEBOX" == name) 
    8384            return FREEBOX; 
     85        if ("R5000" == name) 
     86            return R5000; 
    8487        return ERROR_UNKNOWN; 
    8588    } 
    8689 
     
    8992        return 
    9093            (rawtype != "DVB")       && 
    9194            (rawtype != "FIREWIRE")  && (rawtype != "DBOX2")   && 
    92             (rawtype != "HDHOMERUN") && (rawtype != "FREEBOX"); 
     95            (rawtype != "HDHOMERUN") && (rawtype != "FREEBOX") && 
     96            (rawtype != "R5000"); 
    9397    } 
    9498 
    9599    static bool         IsUnscanable(const QString &rawtype) 
    96100    { 
    97101        return 
    98             (rawtype == "FIREWIRE")  || (rawtype == "DBOX2"); 
     102            (rawtype == "FIREWIRE")  || (rawtype == "DBOX2") || 
     103            (rawtype == "R5000"); 
    99104    } 
    100105 
    101106    static bool         IsEITCapable(const QString &rawtype) 
  • libs/libmythtv/libmythtv.pro

    old new  
    489489        DEFINES += USING_DVB 
    490490    } 
    491491 
     492    #Support for R5000 usb device 
     493    using_r5000 { 
     494        HEADERS += r5000channel.h           r5000recorder.h 
     495        HEADERS += r5000signalmonitor.h     r5000device.h 
     496        HEADERS += r5000/r5000.h            r5000/libusb_augment.h 
     497 
     498        SOURCES += r5000channel.cpp         r5000recorder.cpp 
     499        SOURCES += r5000signalmonitor.cpp   r5000device.cpp 
     500        SOURCES += r5000/r5000.c            r5000/libusb_augment.c 
     501 
     502        LIBS += -lusb 
     503        DEFINES += USING_R5000 
     504    } 
     505 
    492506    DEFINES += USING_BACKEND 
    493507} 
    494508 
  • libs/libmythtv/signalmonitor.h

    old new  
    297297            (cardtype.upper() == "HDTV")      || 
    298298            (cardtype.upper() == "HDHOMERUN") || 
    299299            (cardtype.upper() == "FIREWIRE")  || 
    300             (cardtype.upper() == "FREEBOX")); 
     300            (cardtype.upper() == "FREEBOX")   || 
     301            (cardtype.upper() == "R5000")); 
    301302} 
    302303 
    303304inline bool SignalMonitor::IsSupported(const QString &cardtype) 
  • libs/libmythtv/signalmonitor.cpp

    old new  
    4141#   include "firewirechannel.h" 
    4242#endif 
    4343 
     44#ifdef USING_R5000 
     45#   include "r5000signalmonitor.h" 
     46#   include "r5000channel.h" 
     47#endif 
     48 
    4449#undef DBG_SM 
    4550#define DBG_SM(FUNC, MSG) VERBOSE(VB_CHANNEL, \ 
    4651    "SM("<<channel->GetDevice()<<")::"<<FUNC<<": "<<MSG); 
     
    127132            signalMonitor = new FirewireSignalMonitor(db_cardnum, fc); 
    128133    } 
    129134#endif 
     135#ifdef USING_R5000 
     136    if (cardtype.upper() == "R5000") 
     137    { 
     138        R5000Channel *fc = dynamic_cast<R5000Channel*>(channel); 
     139        if (fc) 
     140            signalMonitor = new R5000SignalMonitor(db_cardnum, fc); 
     141    } 
     142#endif 
    130143 
    131144    if (!signalMonitor) 
    132145    { 
  • libs/libmythtv/cardutil.cpp

    old new  
    14571457    if (("FIREWIRE"  == cardtype) || 
    14581458        ("FREEBOX"   == cardtype) || 
    14591459        ("DBOX2"     == cardtype) || 
    1460         ("HDHOMERUN" == cardtype)) 
     1460        ("HDHOMERUN" == cardtype) || 
     1461        ("R5000"     == cardtype)) 
    14611462    { 
    14621463        ret += "MPEG2TS"; 
    14631464    } 
     
    15821583    if (("FIREWIRE"  == cardtype) || 
    15831584        ("FREEBOX"   == cardtype) || 
    15841585        ("DBOX2"     == cardtype) || 
    1585         ("HDHOMERUN" == cardtype)) 
     1586        ("HDHOMERUN" == cardtype) || 
     1587        ("R5000"     == cardtype)) 
    15861588    { 
    15871589        inputs += "MPEG2TS"; 
    15881590    } 
  • libs/libmythtv/videosource.cpp

    old new  
    12971297    } 
    12981298}; 
    12991299 
     1300class R5000ConfigurationGroup : public VerticalConfigurationGroup 
     1301{ 
     1302  public: 
     1303    R5000ConfigurationGroup(CaptureCard& a_parent): 
     1304       VerticalConfigurationGroup(false, true, false, false), 
     1305       parent(a_parent) 
     1306    { 
     1307        setUseLabel(false); 
     1308        addChild(new SignalTimeout(parent, 2000, 1000)); 
     1309        addChild(new ChannelTimeout(parent, 9000, 1750)); 
     1310        addChild(new SingleCardInput(parent)); 
     1311    }; 
     1312 
     1313  private: 
     1314    CaptureCard &parent; 
     1315}; 
     1316 
    13001317class IPTVHost : public LineEditSetting, public CaptureCardDBStorage 
    13011318{ 
    13021319  public: 
     
    14811498#ifdef USING_IPTV 
    14821499    addTarget("FREEBOX",   new IPTVConfigurationGroup(parent)); 
    14831500#endif // USING_IPTV 
     1501 
     1502#ifdef USING_R5000 
     1503    addTarget("R5000", new R5000ConfigurationGroup(parent)); 
     1504#endif // USING_R5000 
    14841505} 
    14851506 
    14861507void CaptureCardGroup::triggerChanged(const QString& value)  
     
    16681689#ifdef USING_IPTV 
    16691690    setting->addSelection(QObject::tr("Network Recorder"), "FREEBOX"); 
    16701691#endif // USING_IPTV 
     1692 
     1693#ifdef USING_R5000 
     1694    setting->addSelection(QObject::tr("R5000 Capable STB"), "R5000"); 
     1695#endif // USING_R5000 
    16711696} 
    16721697 
    16731698class CardID : public SelectLabelSetting, public CardInputDBStorage 
  • libs/libmythtv/tv_rec.cpp

    old new  
    5050#include "hdhrchannel.h" 
    5151#include "iptvchannel.h" 
    5252#include "firewirechannel.h" 
     53#include "r5000channel.h" 
    5354 
    5455#include "recorderbase.h" 
    5556#include "NuppelVideoRecorder.h" 
     
    5960#include "hdhrrecorder.h" 
    6061#include "iptvrecorder.h" 
    6162#include "firewirerecorder.h" 
     63#include "r5000recorder.h" 
    6264 
    6365#ifdef USING_V4L 
    6466#include "channel.h" 
     
    199201        init_run = true; 
    200202#endif 
    201203    }     
     204    else if (genOpt.cardtype == "R5000") 
     205    { 
     206#ifdef USING_R5000 
     207        channel = new R5000Channel(this, genOpt.videodev, fwOpt); 
     208        if (!channel->Open()) 
     209            return false; 
     210        InitChannel(genOpt.defaultinput, startchannel); 
     211        init_run = true; 
     212#endif 
     213    } 
    202214    else // "V4L" or "MPEG", ie, analog TV 
    203215    { 
    204216#ifdef USING_V4L 
     
    10171029        recorder->SetOption("mrl", genOpt.videodev); 
    10181030#endif // USING_IPTV 
    10191031    } 
     1032    else if (genOpt.cardtype == "R5000") 
     1033    { 
     1034#ifdef USING_R5000 
     1035        recorder = new R5000Recorder(this, GetR5000Channel()); 
     1036#endif // USING_R5000 
     1037    } 
    10201038    else 
    10211039    { 
    10221040#ifdef USING_V4L 
     
    12301248#endif // USING_FIREWIRE 
    12311249} 
    12321250 
     1251R5000Channel *TVRec::GetR5000Channel(void) 
     1252{ 
     1253#ifdef USING_R5000 
     1254    return dynamic_cast<R5000Channel*>(channel); 
     1255#else 
     1256    return NULL; 
     1257#endif // USING_R5000 
     1258} 
     1259 
    12331260Channel *TVRec::GetV4LChannel(void) 
    12341261{ 
    12351262#ifdef USING_V4L 
  • libs/libmythtv/transporteditor.cpp

    old new  
    735735        left->addChild(new Modulation(id, nType)); 
    736736    } 
    737737    else if ((CardUtil::FIREWIRE == nType) || 
    738              (CardUtil::FREEBOX  == nType)) 
     738             (CardUtil::FREEBOX  == nType) || 
     739             (CardUtil::R5000    == nType)) 
    739740    { 
    740741        left->addChild(new DTVStandard(id, true, true)); 
    741742    } 
  • libs/libmythtv/tv_rec.h

    old new  
    3939class FirewireChannel; 
    4040class Channel; 
    4141class HDHRChannel; 
     42class R5000Channel; 
    4243 
    4344class MPEGStreamData; 
    4445class ProgramMapTable; 
     
    281282    HDHRChannel  *GetHDHRChannel(void); 
    282283    DVBChannel   *GetDVBChannel(void); 
    283284    FirewireChannel *GetFirewireChannel(void); 
     285    R5000Channel *GetR5000Channel(void); 
    284286    Channel      *GetV4LChannel(void); 
    285287 
    286288    bool SetupSignalMonitor(bool enable_table_monitoring, bool notify); 
  • new file libs/libmythtv/r5000channel.cpp

    - +  
     1/** 
     2 *  R5000Channel 
     3 *  Copyright (c) 2005 by Jim Westfall, Dave Abrahams 
     4 *  Copyright (c) 2006 by Daniel Kristjansson 
     5 *  Distributed as part of MythTV under GPL v2 and later. 
     6 */ 
     7 
     8#include "mythcontext.h" 
     9#include "tv_rec.h" 
     10#include "r5000channel.h" 
     11 
     12#define LOC QString("R5kChan(%1): ").arg(GetDevice()) 
     13#define LOC_WARN QString("R5kChan(%1), Warning: ").arg(GetDevice()) 
     14#define LOC_ERR QString("R5kChan(%1), Error: ").arg(GetDevice()) 
     15 
     16R5000Channel::R5000Channel(TVRec *parent, const QString &_videodevice,const FireWireDBOptions &firewire_opts) : 
     17    DTVChannel(parent), 
     18    videodevice(_videodevice), 
     19    fw_opts(firewire_opts), 
     20    device(NULL), 
     21    current_channel(0), 
     22    isopen(false) 
     23{ 
     24    uint subunitid = 0; // we only support first tuner on STB... 
     25 
     26    device = new R5000Device(0, subunitid, fw_opts.speed); 
     27 
     28    InitializeInputs(); 
     29} 
     30 
     31bool R5000Channel::SetChannelByString(const QString &channum) 
     32{ 
     33    QString loc = LOC + QString("SetChannelByString(%1)").arg(channum); 
     34    bool ok = true; 
     35    VERBOSE(VB_CHANNEL, loc); 
     36 
     37    InputMap::const_iterator it = inputs.find(currentInputID); 
     38    if (it == inputs.end()) 
     39        return false; 
     40 
     41    QString tvformat, modulation, freqtable, freqid, dtv_si_std; 
     42    int finetune; 
     43    uint64_t frequency; 
     44    int mpeg_prog_num; 
     45    uint atsc_major, atsc_minor, mplexid, tsid, netid; 
     46    if (!ChannelUtil::GetChannelData( 
     47        (*it)->sourceid, channum, 
     48        tvformat, modulation, freqtable, freqid, 
     49        finetune, frequency, 
     50        dtv_si_std, mpeg_prog_num, atsc_major, atsc_minor, tsid, netid, 
     51        mplexid, commfree)) 
     52    { 
     53        VERBOSE(VB_IMPORTANT, loc + " " + QString( 
     54                    "Requested channel '%1' is on input '%2' " 
     55                    "which is in a busy input group") 
     56                .arg(channum).arg(currentInputID)); 
     57 
     58        return false; 
     59    } 
     60    uint mplexid_restriction; 
     61    if (!IsInputAvailable(currentInputID, mplexid_restriction)) 
     62    { 
     63        VERBOSE(VB_IMPORTANT, loc + " " + QString( 
     64                    "Requested channel '%1' is on input '%2' " 
     65                    "which is in a busy input group") 
     66                .arg(channum).arg(currentInputID)); 
     67 
     68        return false; 
     69    } 
     70 
     71    uint ichan = freqid.toUInt(&ok); 
     72    ok = isopen && SetChannelByNumber(ichan); 
     73 
     74    if (ok) 
     75    { 
     76        // Set the current channum to the new channel's channum 
     77        curchannelname = QDeepCopy<QString>(channum); 
     78        (*it)->startChanNum = QDeepCopy<QString>(channum); 
     79    } 
     80 
     81    VERBOSE(VB_CHANNEL, loc + " " + ((ok) ? "success" : "failure")); 
     82 
     83    return ok; 
     84} 
     85 
     86bool R5000Channel::Open(void) 
     87{ 
     88    VERBOSE(VB_CHANNEL, LOC + "Open()"); 
     89 
     90    if (inputs.find(currentInputID) == inputs.end()) 
     91        return false; 
     92 
     93    if (!device) 
     94        return false; 
     95 
     96    if (isopen) 
     97        return true; 
     98 
     99    if (!device->OpenPort()) 
     100        return false; 
     101 
     102    isopen = true; 
     103 
     104    return true; 
     105} 
     106 
     107void R5000Channel::Close(void) 
     108{ 
     109    VERBOSE(VB_CHANNEL, LOC + "Close()"); 
     110    if (isopen) 
     111    { 
     112        device->ClosePort(); 
     113        isopen = false; 
     114    } 
     115} 
     116 
     117QString R5000Channel::GetDevice(void) const 
     118{ 
     119    return videodevice; 
     120} 
     121 
     122bool R5000Channel::SetPowerState(bool on) 
     123{ 
     124    if (!isopen) 
     125    { 
     126        VERBOSE(VB_IMPORTANT, LOC_ERR + 
     127                "SetPowerState() called on closed R5000Channel."); 
     128 
     129        return false; 
     130    } 
     131 
     132    return device->SetPowerState(on); 
     133} 
     134 
     135R5000Device::PowerState R5000Channel::GetPowerState(void) const 
     136{ 
     137    if (!isopen) 
     138    { 
     139        VERBOSE(VB_IMPORTANT, LOC_ERR + 
     140                "GetPowerState() called on closed R5000Channel."); 
     141 
     142        return R5000Device::kAVCPowerQueryFailed; 
     143    } 
     144 
     145    return device->GetPowerState(); 
     146} 
     147 
     148bool R5000Channel::Retune(void) 
     149{ 
     150    VERBOSE(VB_CHANNEL, LOC + "Retune()"); 
     151 
     152    if (R5000Device::kAVCPowerOff == GetPowerState()) 
     153    { 
     154        VERBOSE(VB_IMPORTANT, LOC_ERR + 
     155                "STB is turned off, must be on to retune."); 
     156 
     157        return false; 
     158    } 
     159 
     160    if (current_channel) 
     161        return SetChannelByNumber(current_channel); 
     162 
     163    return false; 
     164} 
     165 
     166bool R5000Channel::SetChannelByNumber(int channel) 
     167{ 
     168    VERBOSE(VB_CHANNEL, QString("SetChannelByNumber(%1)").arg(channel)); 
     169    current_channel = channel; 
     170 
     171    if (R5000Device::kAVCPowerOff == GetPowerState()) 
     172    { 
     173        VERBOSE(VB_IMPORTANT, LOC_WARN + 
     174                "STB is turned off, must be on to set channel."); 
     175 
     176        SetSIStandard("mpeg"); 
     177        SetDTVInfo(0,0,0,0,1); 
     178 
     179        return true; // signal monitor will call retune later... 
     180    } 
     181 
     182    if (!device->SetChannel(fw_opts.model, 0, channel)) 
     183        return false; 
     184 
     185    SetSIStandard("mpeg"); 
     186    SetDTVInfo(0,0,0,0,1); 
     187 
     188    return true; 
     189} 
  • new file libs/libmythtv/r5000device.cpp

    - +  
     1/** 
     2 *  R5000Device 
     3 *  Copyright (c) 2008 by Alan Nisota 
     4 *  Copyright (c) 2005 by Jim Westfall 
     5 *  Distributed as part of MythTV under GPL v2 and later. 
     6 */ 
     7 
     8// Qt headers 
     9#include <qdeepcopy.h> 
     10 
     11// MythTV headers 
     12#include "r5000device.h" 
     13#include "mythcontext.h" 
     14#include "pespacket.h" 
     15 
     16#define LOC      QString("R5kDev: ") 
     17#define LOC_WARN QString("R5kDev, Warning: ") 
     18#define LOC_ERR  QString("R5kDev, Error: ") 
     19 
     20static void fw_init(QMap<uint64_t,QString> &id_to_model); 
     21 
     22QMap<uint64_t,QString> R5000Device::s_id_to_model; 
     23QMutex                 R5000Device::s_static_lock; 
     24 
     25unsigned int r5000_device_tspacket_handler(unsigned char *tspacket, int len, void *callback_data) 
     26{ 
     27    R5000Device *fw = (R5000Device*) callback_data; 
     28    if (! fw) 
     29        return 0; 
     30    if (len > 0) 
     31        fw->BroadcastToListeners(tspacket, len); 
     32    return 1; 
     33} 
     34 
     35 
     36class R5kPriv 
     37{ 
     38  public: 
     39    R5kPriv() : 
     40        reset_timer_on(false), 
     41        run_port_handler(false), is_port_handler_running(false), 
     42        channel(-1), 
     43        is_streaming(false) 
     44    { 
     45    } 
     46 
     47    bool             reset_timer_on; 
     48    MythTimer        reset_timer; 
     49 
     50    bool             run_port_handler; 
     51    bool             is_port_handler_running; 
     52    QMutex           start_stop_port_handler_lock; 
     53 
     54    int              channel; 
     55 
     56    bool             is_streaming; 
     57 
     58    QDateTime        stop_streaming_timer; 
     59    pthread_t        port_handler_thread; 
     60 
     61    static QMutex           s_lock; 
     62}; 
     63QMutex          R5kPriv::s_lock; 
     64 
     65//callback functions 
     66void *r5000_device_port_handler_thunk(void *param); 
     67 
     68R5000Device::R5000Device(uint64_t guid, uint subunitid, uint speed) : 
     69    m_guid(guid),           m_subunitid(subunitid), 
     70    m_speed(speed), 
     71    m_last_channel(0),      m_last_crc(0), 
     72    m_buffer_cleared(true), m_open_port_cnt(0), 
     73    m_lock(false),          m_priv(new R5kPriv()) 
     74{ 
     75  usbdev = NULL; 
     76} 
     77 
     78R5000Device::~R5000Device() 
     79{ 
     80    if (usbdev) 
     81    { 
     82        VERBOSE(VB_IMPORTANT, LOC_ERR + "ctor called with open port"); 
     83        while(usbdev) 
     84            ClosePort(); 
     85    } 
     86 
     87    if (m_priv) 
     88    { 
     89        delete m_priv; 
     90        m_priv = NULL; 
     91    } 
     92} 
     93 
     94void R5000Device::AddListener(TSDataListener *listener) 
     95{ 
     96    if (listener) 
     97    { 
     98        vector<TSDataListener*>::iterator it = 
     99            find(m_listeners.begin(), m_listeners.end(), listener); 
     100 
     101        if (it == m_listeners.end()) 
     102            m_listeners.push_back(listener); 
     103    } 
     104 
     105    VERBOSE(VB_RECORD, LOC + "AddListener() "<<m_listeners.size()); 
     106    if (!m_listeners.empty()) 
     107    { 
     108        StartStreaming(); 
     109    } 
     110} 
     111 
     112void R5000Device::RemoveListener(TSDataListener *listener) 
     113{ 
     114    vector<TSDataListener*>::iterator it = m_listeners.end(); 
     115 
     116    do 
     117    { 
     118        it = find(m_listeners.begin(), m_listeners.end(), listener); 
     119        if (it != m_listeners.end()) 
     120            m_listeners.erase(it); 
     121    } 
     122    while (it != m_listeners.end()); 
     123 
     124    VERBOSE(VB_RECORD, LOC + "RemoveListener() "<<m_listeners.size()); 
     125    if (m_listeners.empty()) 
     126    { 
     127        StopStreaming(); 
     128    } 
     129} 
     130 
     131bool R5000Device::StartStreaming(void) 
     132{ 
     133    if (m_priv->is_streaming) 
     134        return m_priv->is_streaming; 
     135 
     136    if (! usbdev) 
     137    { 
     138        VERBOSE(VB_IMPORTANT, LOC_ERR + "Device not open"); 
     139        return false; 
     140    } 
     141    if (r5000_start_stream(usbdev)) 
     142    { 
     143        m_priv->is_streaming = true; 
     144    } 
     145    else 
     146    { 
     147        VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting A/V streaming "); 
     148    } 
     149 
     150    VERBOSE(VB_RECORD, LOC + "Starting A/V streaming -- done"); 
     151 
     152    return m_priv->is_streaming; 
     153} 
     154 
     155bool R5000Device::StopStreaming(void) 
     156{ 
     157    if (m_priv->is_streaming) 
     158    { 
     159        VERBOSE(VB_RECORD, LOC + "Stopping A/V streaming -- really"); 
     160 
     161        m_priv->is_streaming = false; 
     162 
     163        r5000_stop_stream(usbdev); 
     164    } 
     165 
     166    VERBOSE(VB_RECORD, LOC + "Stopped A/V streaming"); 
     167 
     168    return true; 
     169} 
     170 
     171bool R5000Device::SetPowerState(bool on) 
     172{ 
     173    QMutexLocker locker(&m_lock); 
     174    QString cmdStr = (on) ? "on" : "off"; 
     175    VERBOSE(VB_RECORD, LOC + QString("Powering %1").arg(cmdStr)); 
     176    if(r5000_get_power_state(usbdev) != on) 
     177      r5000_toggle_on_off(usbdev); 
     178    return true; 
     179} 
     180 
     181R5000Device::PowerState R5000Device::GetPowerState(void) 
     182{ 
     183    QMutexLocker locker(&m_lock); 
     184    int on_off; 
     185 
     186    VERBOSE(VB_CHANNEL, LOC + "Requesting STB Power State"); 
     187    on_off = r5000_get_power_state(usbdev); 
     188    VERBOSE(VB_CHANNEL, LOC + (on_off ? "On" : "Off")); 
     189    return on_off ? kAVCPowerOn : kAVCPowerOff; 
     190} 
     191 
     192bool R5000Device::SetChannel(const QString &panel_model, 
     193                                uint alt_method, uint channel) 
     194{ 
     195    VERBOSE(VB_CHANNEL, QString("SetChannel(model %1, alt %2, chan %3)") 
     196            .arg(panel_model).arg(alt_method).arg(channel)); 
     197 
     198    QMutexLocker locker(&m_lock); 
     199    VERBOSE(VB_CHANNEL, "SetChannel() -- locked"); 
     200    r5000_change_channel(usbdev, channel); 
     201    return true; 
     202} 
     203 
     204void R5000Device::BroadcastToListeners( 
     205    const unsigned char *data, uint dataSize) 
     206{ 
     207    if ((dataSize >= TSPacket::SIZE) && (data[0] == SYNC_BYTE) && 
     208        ((data[1] & 0x1f) == 0) && (data[2] == 0)) 
     209    { 
     210        ProcessPATPacket(*((const TSPacket*)data)); 
     211    } 
     212 
     213    vector<TSDataListener*>::iterator it = m_listeners.begin(); 
     214    for (; it != m_listeners.end(); ++it) 
     215        (*it)->AddData(data, dataSize); 
     216} 
     217 
     218void R5000Device::SetLastChannel(const uint channel) 
     219{ 
     220    m_buffer_cleared = (channel == m_last_channel); 
     221    m_last_channel   = channel; 
     222 
     223    VERBOSE(VB_IMPORTANT, QString("SetLastChannel(%1): cleared: %2") 
     224            .arg(channel).arg(m_buffer_cleared ? "yes" : "no")); 
     225} 
     226 
     227void R5000Device::ProcessPATPacket(const TSPacket &tspacket) 
     228{ 
     229    if (!tspacket.TransportError() && !tspacket.ScramplingControl() && 
     230        tspacket.HasPayload() && tspacket.PayloadStart() && !tspacket.PID()) 
     231    { 
     232        PESPacket pes = PESPacket::View(tspacket); 
     233        uint crc = pes.CalcCRC(); 
     234        m_buffer_cleared |= (crc != m_last_crc); 
     235        m_last_crc = crc; 
     236#if 0 
     237        VERBOSE(VB_RECORD, LOC + 
     238                QString("ProcessPATPacket: CRC 0x%1 cleared: %2") 
     239                .arg(crc,0,16).arg(m_buffer_cleared ? "yes" : "no")); 
     240#endif 
     241    } 
     242    else 
     243    { 
     244        VERBOSE(VB_IMPORTANT, LOC_ERR + "Can't handle large PAT's"); 
     245    } 
     246} 
     247 
     248QString R5000Device::GetModelName(uint vendor_id, uint model_id) 
     249{ 
     250    QMutexLocker locker(&s_static_lock); 
     251/* 
     252    if (s_id_to_model.empty()) 
     253        fw_init(s_id_to_model); 
     254 
     255    QString ret = s_id_to_model[(((uint64_t) vendor_id) << 32) | model_id]; 
     256 
     257    if (ret.isEmpty()) 
     258        return "GENERIC"; 
     259*/ 
     260    return "R5000"; 
     261} 
     262 
     263bool R5000Device::IsSTBSupported(const QString &panel_model) 
     264{ 
     265    return true; 
     266} 
     267 
     268bool R5000Device::OpenPort(void) 
     269{ 
     270    VERBOSE(VB_RECORD, LOC + "Starting Port Handler Thread"); 
     271    QMutexLocker mlocker(&m_lock); 
     272    VERBOSE(VB_RECORD, LOC + "Starting Port Handler Thread -- locked"); 
     273    if(usbdev) { 
     274        m_open_port_cnt++; 
     275        return true; 
     276    } 
     277 
     278    usbdev = r5000_open(r5000_device_tspacket_handler, this, 0); 
     279    if(! usbdev) 
     280        return false; 
     281 
     282    VERBOSE(VB_RECORD, LOC + "Starting port handler thread"); 
     283    m_priv->run_port_handler = true; 
     284    pthread_create(&m_priv->port_handler_thread, NULL, 
     285                   r5000_device_port_handler_thunk, this); 
     286 
     287    VERBOSE(VB_RECORD, LOC + "Waiting for port handler thread to start"); 
     288    while (!m_priv->is_port_handler_running) 
     289    { 
     290        m_lock.unlock(); 
     291        usleep(5000); 
     292        m_lock.lock(); 
     293    } 
     294 
     295    VERBOSE(VB_RECORD, LOC + "Port handler thread started"); 
     296 
     297    m_open_port_cnt++; 
     298 
     299    return true; 
     300} 
     301 
     302bool R5000Device::ClosePort(void) 
     303{ 
     304    VERBOSE(VB_RECORD, LOC + "Stopping Port Handler Thread"); 
     305    QMutexLocker locker(&m_priv->start_stop_port_handler_lock); 
     306    VERBOSE(VB_RECORD, LOC + "Stopping Port Handler Thread -- locked"); 
     307 
     308    QMutexLocker mlocker(&m_lock); 
     309 
     310    VERBOSE(VB_RECORD, LOC + "ClosePort()"); 
     311 
     312    if (m_open_port_cnt < 1) 
     313        return false; 
     314 
     315    m_open_port_cnt--; 
     316 
     317    if (m_open_port_cnt != 0) 
     318        return true; 
     319 
     320    if (!usbdev) 
     321        return false; 
     322 
     323    VERBOSE(VB_RECORD, LOC + "Waiting for port handler thread to stop"); 
     324    m_priv->run_port_handler = false; 
     325    while (m_priv->is_port_handler_running) 
     326    { 
     327        m_lock.unlock(); 
     328        usleep(5000); 
     329        m_lock.lock(); 
     330    } 
     331    VERBOSE(VB_RECORD, LOC + "Joining port handler thread"); 
     332    pthread_join(m_priv->port_handler_thread, NULL); 
     333 
     334    r5000_close(usbdev); 
     335    usbdev = NULL; 
     336 
     337    return true; 
     338} 
     339 
     340void *r5000_device_port_handler_thunk(void *param) 
     341{ 
     342    R5000Device *mon = (R5000Device*) param; 
     343    mon->RunPortHandler(); 
     344    return NULL; 
     345} 
     346 
     347void R5000Device::RunPortHandler(void) 
     348{ 
     349    VERBOSE(VB_RECORD, LOC + "RunPortHandler -- start"); 
     350    m_lock.lock(); 
     351    VERBOSE(VB_RECORD, LOC + "RunPortHandler -- got first lock"); 
     352    m_priv->is_port_handler_running = true; 
     353    m_lock.unlock(); 
     354 
     355    while (m_priv->run_port_handler) 
     356    { 
     357        if (m_priv->is_streaming) { 
     358            // This will timeout after 10ms regardless of data availability 
     359            r5000_loop_iterate(usbdev, 10); 
     360        } else { 
     361            usleep(10000); 
     362        } 
     363    } 
     364 
     365    m_lock.lock(); 
     366    m_priv->is_port_handler_running = false; 
     367    m_lock.unlock(); 
     368    VERBOSE(VB_RECORD, LOC + "RunPortHandler -- end"); 
     369} 
  • new file libs/libmythtv/r5000recorder.cpp

    - +  
     1/** 
     2 *  R5000Recorder 
     3 *  Copyright (c) 2005 by Jim Westfall and Dave Abrahams 
     4 *  Distributed as part of MythTV under GPL v2 and later. 
     5 */ 
     6 
     7// MythTV includes 
     8#include "r5000recorder.h" 
     9#include "r5000channel.h" 
     10#include "mythcontext.h" 
     11#include "mpegtables.h" 
     12#include "mpegstreamdata.h" 
     13#include "tv_rec.h" 
     14 
     15#define LOC QString("R5000RecBase(%1): ").arg(channel->GetDevice()) 
     16#define LOC_ERR QString("R5000RecBase(%1), Error: ").arg(channel->GetDevice()) 
     17 
     18R5000Recorder::R5000Recorder(TVRec *rec, R5000Channel *chan) : 
     19    DTVRecorder(rec), _mpeg_stream_data(NULL), 
     20    channel(chan), isopen(false) 
     21{ 
     22} 
     23 
     24R5000Recorder::~R5000Recorder() 
     25{ 
     26    SetStreamData(NULL); 
     27    Close(); 
     28} 
     29 
     30bool R5000Recorder::Open(void) 
     31{ 
     32    if (!isopen) 
     33        isopen = channel->GetR5000Device()->OpenPort(); 
     34 
     35    return isopen; 
     36} 
     37 
     38void R5000Recorder::Close(void) 
     39{ 
     40    if (isopen) 
     41    { 
     42        channel->GetR5000Device()->ClosePort(); 
     43        isopen = false; 
     44    } 
     45} 
     46 
     47void R5000Recorder::StartStreaming(void) 
     48{ 
     49    channel->GetR5000Device()->AddListener(this); 
     50} 
     51 
     52void R5000Recorder::StopStreaming(void) 
     53{ 
     54    channel->GetR5000Device()->RemoveListener(this); 
     55} 
     56 
     57void R5000Recorder::StartRecording(void) 
     58{ 
     59    VERBOSE(VB_RECORD, LOC + "StartRecording"); 
     60 
     61    if (!Open()) 
     62    { 
     63        _error = true; 
     64        return; 
     65    } 
     66 
     67    _request_recording = true; 
     68    _recording = true; 
     69 
     70    StartStreaming(); 
     71 
     72    while (_request_recording) 
     73    { 
     74        if (!PauseAndWait()) 
     75            usleep(50 * 1000); 
     76    } 
     77 
     78    StopStreaming(); 
     79    FinishRecording(); 
     80 
     81    _recording = false; 
     82} 
     83 
     84void R5000Recorder::AddData(const unsigned char *data, uint len) 
     85{ 
     86    uint bufsz = buffer.size(); 
     87    if ((SYNC_BYTE == data[0]) && (TSPacket::SIZE == len) && 
     88        (TSPacket::SIZE > bufsz)) 
     89    { 
     90        if (bufsz) 
     91            buffer.clear(); 
     92 
     93        ProcessTSPacket(*(reinterpret_cast<const TSPacket*>(data))); 
     94        return; 
     95    } 
     96 
     97    buffer.insert(buffer.end(), data, data + len); 
     98    bufsz += len; 
     99 
     100    int sync_at = -1; 
     101    for (uint i = 0; (i < bufsz) && (sync_at < 0); i++) 
     102    { 
     103        if (buffer[i] == SYNC_BYTE) 
     104            sync_at = i; 
     105    } 
     106 
     107    if (sync_at < 0) 
     108        return; 
     109 
     110    if (bufsz < 30 * TSPacket::SIZE) 
     111        return; // build up a little buffer 
     112 
     113    while (sync_at + TSPacket::SIZE < bufsz) 
     114    { 
     115        ProcessTSPacket(*(reinterpret_cast<const TSPacket*>( 
     116                              &buffer[0] + sync_at))); 
     117 
     118        sync_at += TSPacket::SIZE; 
     119    } 
     120 
     121    buffer.erase(buffer.begin(), buffer.begin() + sync_at); 
     122 
     123    return; 
     124} 
     125 
     126void R5000Recorder::ProcessTSPacket(const TSPacket &tspacket) 
     127{ 
     128    if (tspacket.TransportError()) 
     129        return; 
     130 
     131    if (tspacket.ScramplingControl()) 
     132        return; 
     133 
     134    if (tspacket.HasAdaptationField()) 
     135        GetStreamData()->HandleAdaptationFieldControl(&tspacket); 
     136 
     137    if (tspacket.HasPayload()) 
     138    { 
     139        const unsigned int lpid = tspacket.PID(); 
     140        // Pass or reject packets based on PID, and parse info from them 
     141        if (lpid == GetStreamData()->VideoPIDSingleProgram()) 
     142        { 
     143            _buffer_packets = !FindMPEG2Keyframes(&tspacket); 
     144            BufferedWrite(tspacket); 
     145        } 
     146        else if (GetStreamData()->IsAudioPID(lpid)) 
     147        { 
     148            _buffer_packets = !FindAudioKeyframes(&tspacket); 
     149            BufferedWrite(tspacket); 
     150        } 
     151        else if (GetStreamData()->IsListeningPID(lpid)) 
     152            GetStreamData()->HandleTSTables(&tspacket); 
     153        else if (GetStreamData()->IsWritingPID(lpid)) 
     154            BufferedWrite(tspacket); 
     155    } 
     156} 
     157 
     158void R5000Recorder::SetOptionsFromProfile(RecordingProfile *profile, 
     159                                                 const QString &videodev, 
     160                                                 const QString &audiodev, 
     161                                                 const QString &vbidev) 
     162{ 
     163    (void)videodev; 
     164    (void)audiodev; 
     165    (void)vbidev; 
     166    (void)profile; 
     167} 
     168 
     169// documented in recorderbase.cpp 
     170bool R5000Recorder::PauseAndWait(int timeout) 
     171{ 
     172    if (request_pause) 
     173    { 
     174        VERBOSE(VB_RECORD, LOC + "PauseAndWait("<<timeout<<") -- pause"); 
     175        if (!paused) 
     176        { 
     177            StopStreaming(); 
     178            paused = true; 
     179            pauseWait.wakeAll(); 
     180            if (tvrec) 
     181                tvrec->RecorderPaused(); 
     182        } 
     183        unpauseWait.wait(timeout); 
     184    } 
     185    if (!request_pause && paused) 
     186    { 
     187        VERBOSE(VB_RECORD, LOC + "PauseAndWait("<<timeout<<") -- unpause"); 
     188        StartStreaming(); 
     189        paused = false; 
     190    } 
     191    return paused; 
     192} 
     193 
     194void R5000Recorder::SetStreamData(MPEGStreamData *data) 
     195{ 
     196    VERBOSE(VB_RECORD, LOC + "SetStreamData("<<data<<") -- begin"); 
     197    if (data == _mpeg_stream_data) 
     198    { 
     199        VERBOSE(VB_RECORD, LOC + "SetStreamData("<<data<<") -- end 0"); 
     200        return; 
     201    } 
     202 
     203    MPEGStreamData *old_data = _mpeg_stream_data; 
     204    _mpeg_stream_data = data; 
     205    if (old_data) 
     206        delete old_data; 
     207 
     208    if (data) 
     209    { 
     210        data->AddMPEGSPListener(this); 
     211 
     212        if (data->DesiredProgram() >= 0) 
     213            data->SetDesiredProgram(data->DesiredProgram()); 
     214    } 
     215    VERBOSE(VB_RECORD, LOC + "SetStreamData("<<data<<") -- end 1"); 
     216} 
     217 
     218void R5000Recorder::HandleSingleProgramPAT(ProgramAssociationTable *pat) 
     219{ 
     220    if (!pat) { 
     221        VERBOSE(VB_RECORD, LOC + "HandleSingleProgramPAT(NULL)"); 
     222        return; 
     223    } 
     224    int next = (pat->tsheader()->ContinuityCounter()+1)&0xf; 
     225    pat->tsheader()->SetContinuityCounter(next); 
     226    BufferedWrite(*(reinterpret_cast<const TSPacket*>(pat->tsheader()))); 
     227} 
     228 
     229void R5000Recorder::HandleSingleProgramPMT(ProgramMapTable *pmt) 
     230{ 
     231    if (!pmt) { 
     232        VERBOSE(VB_RECORD, LOC + "HandleSingleProgramPMT(NULL)"); 
     233        return; 
     234    } 
     235    int next = (pmt->tsheader()->ContinuityCounter()+1)&0xf; 
     236    pmt->tsheader()->SetContinuityCounter(next); 
     237    BufferedWrite(*(reinterpret_cast<const TSPacket*>(pmt->tsheader()))); 
     238} 
  • new file libs/libmythtv/r5000signalmonitor.cpp

    - +  
     1// -*- Mode: c++ -*- 
     2// Copyright (c) 2006, Daniel Thor Kristjansson 
     3 
     4#include <pthread.h> 
     5#include <fcntl.h> 
     6#include <unistd.h> 
     7#include <sys/select.h> 
     8 
     9#include "mythcontext.h" 
     10#include "mythdbcon.h" 
     11#include "atscstreamdata.h" 
     12#include "mpegtables.h" 
     13#include "atsctables.h" 
     14#include "r5000channel.h" 
     15#include "r5000signalmonitor.h" 
     16 
     17#define LOC QString("R5kSM(%1): ").arg(channel->GetDevice()) 
     18#define LOC_WARN QString("R5kSM(%1), Warning: ").arg(channel->GetDevice()) 
     19#define LOC_ERR QString("R5kSM(%1), Error: ").arg(channel->GetDevice()) 
     20 
     21const uint R5000SignalMonitor::kPowerTimeout  = 3000; /* ms */ 
     22const uint R5000SignalMonitor::kBufferTimeout = 5000; /* ms */ 
     23 
     24QMap<void*,uint> R5000SignalMonitor::pat_keys; 
     25QMutex           R5000SignalMonitor::pat_keys_lock; 
     26 
     27/** \fn R5000SignalMonitor::R5000SignalMonitor(int,R5000Channel*,uint,const char*) 
     28 *  \brief Initializes signal lock and signal values. 
     29 * 
     30 *   Start() must be called to actually begin continuous 
     31 *   signal monitoring. The timeout is set to 3 seconds, 
     32 *   and the signal threshold is initialized to 0%. 
     33 * 
     34 *  \param db_cardnum Recorder number to monitor, 
     35 *                    if this is less than 0, SIGNAL events will not be 
     36 *                    sent to the frontend even if SetNotifyFrontend(true) 
     37 *                    is called. 
     38 *  \param _channel R5000Channel for card 
     39 *  \param _flags   Flags to start with 
     40 *  \param _name    Name for Qt signal debugging 
     41 */ 
     42R5000SignalMonitor::R5000SignalMonitor( 
     43    int db_cardnum, 
     44    R5000Channel *_channel, 
     45    uint64_t _flags, const char *_name) : 
     46    DTVSignalMonitor(db_cardnum, _channel, _flags, _name), 
     47    dtvMonitorRunning(false), 
     48    stb_needs_retune(true), 
     49    stb_needs_to_wait_for_pat(false), 
     50    stb_needs_to_wait_for_power(false) 
     51{ 
     52    VERBOSE(VB_CHANNEL, LOC + "ctor"); 
     53 
     54    signalStrength.SetThreshold(65); 
     55 
     56    AddFlags(kDTVSigMon_WaitForSig); 
     57 
     58    stb_needs_retune = 
     59        (R5000Device::kAVCPowerOff == _channel->GetPowerState()); 
     60} 
     61 
     62/** \fn R5000SignalMonitor::~R5000SignalMonitor() 
     63 *  \brief Stops signal monitoring and table monitoring threads. 
     64 */ 
     65R5000SignalMonitor::~R5000SignalMonitor() 
     66{ 
     67    VERBOSE(VB_CHANNEL, LOC + "dtor"); 
     68    Stop(); 
     69} 
     70 
     71void R5000SignalMonitor::deleteLater(void) 
     72{ 
     73    disconnect(); // disconnect signals we may be sending... 
     74    Stop(); 
     75    DTVSignalMonitor::deleteLater(); 
     76} 
     77 
     78/** \fn R5000SignalMonitor::Stop(void) 
     79 *  \brief Stop signal monitoring and table monitoring threads. 
     80 */ 
     81void R5000SignalMonitor::Stop(void) 
     82{ 
     83    VERBOSE(VB_CHANNEL, LOC + "Stop() -- begin"); 
     84    SignalMonitor::Stop(); 
     85    if (dtvMonitorRunning) 
     86    { 
     87        dtvMonitorRunning = false; 
     88        pthread_join(table_monitor_thread, NULL); 
     89    } 
     90    VERBOSE(VB_CHANNEL, LOC + "Stop() -- end"); 
     91} 
     92 
     93void R5000SignalMonitor::HandlePAT(const ProgramAssociationTable *pat) 
     94{ 
     95    AddFlags(kDTVSigMon_PATSeen); 
     96 
     97    R5000Channel *fwchan = dynamic_cast<R5000Channel*>(channel); 
     98    bool crc_bogus = !fwchan->GetR5000Device()->IsSTBBufferCleared(); 
     99    if (crc_bogus && stb_needs_to_wait_for_pat && 
     100        (stb_wait_for_pat_timer.elapsed() < (int)kBufferTimeout)) 
     101    { 
     102        VERBOSE(VB_CHANNEL, LOC + "HandlePAT() ignoring PAT"); 
     103        uint tsid = pat->TransportStreamID(); 
     104        GetStreamData()->SetVersionPAT(tsid, -1,0); 
     105        return; 
     106    } 
     107 
     108    if (crc_bogus && stb_needs_to_wait_for_pat) 
     109    { 
     110        VERBOSE(VB_IMPORTANT, LOC_WARN + "Wait for valid PAT timed out"); 
     111        stb_needs_to_wait_for_pat = false; 
     112    } 
     113 
     114    DTVSignalMonitor::HandlePAT(pat); 
     115} 
     116 
     117void R5000SignalMonitor::HandlePMT(uint pnum, const ProgramMapTable *pmt) 
     118{ 
     119    VERBOSE(VB_CHANNEL, LOC + "HandlePMT()"); 
     120 
     121    AddFlags(kDTVSigMon_PMTSeen); 
     122 
     123    if (!HasFlags(kDTVSigMon_PATMatch)) 
     124    { 
     125        GetStreamData()->SetVersionPMT(pnum, -1,0); 
     126        VERBOSE(VB_CHANNEL, LOC + "HandlePMT() ignoring PMT"); 
     127        return; 
     128    } 
     129 
     130    DTVSignalMonitor::HandlePMT(pnum, pmt); 
     131} 
     132 
     133void *R5000SignalMonitor::TableMonitorThread(void *param) 
     134{ 
     135    R5000SignalMonitor *mon = (R5000SignalMonitor*) param; 
     136    mon->RunTableMonitor(); 
     137    return NULL; 
     138} 
     139 
     140void R5000SignalMonitor::RunTableMonitor(void) 
     141{ 
     142    stb_needs_to_wait_for_pat = true; 
     143    stb_wait_for_pat_timer.start(); 
     144    dtvMonitorRunning = true; 
     145 
     146    VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- begin"); 
     147 
     148    R5000Channel *lchan = dynamic_cast<R5000Channel*>(channel); 
     149    if (!lchan) 
     150    { 
     151        VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- err end"); 
     152        dtvMonitorRunning = false; 
     153        return; 
     154    } 
     155 
     156    R5000Device *dev = lchan->GetR5000Device(); 
     157 
     158    dev->OpenPort(); 
     159    dev->AddListener(this); 
     160 
     161    while (dtvMonitorRunning && GetStreamData()) 
     162        usleep(100000); 
     163 
     164    VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- shutdown "); 
     165 
     166    dev->RemoveListener(this); 
     167    dev->ClosePort(); 
     168 
     169    dtvMonitorRunning = false; 
     170 
     171    VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- end"); 
     172} 
     173 
     174void R5000SignalMonitor::AddData(const unsigned char *data, uint len) 
     175{ 
     176    if (!dtvMonitorRunning) 
     177        return; 
     178 
     179    if (GetStreamData()) 
     180        GetStreamData()->ProcessData((unsigned char *)data, len); 
     181} 
     182 
     183/** \fn R5000SignalMonitor::UpdateValues(void) 
     184 *  \brief Fills in frontend stats and emits status Qt signals. 
     185 * 
     186 *   This function uses five ioctl's FE_READ_SNR, FE_READ_SIGNAL_STRENGTH 
     187 *   FE_READ_BER, FE_READ_UNCORRECTED_BLOCKS, and FE_READ_STATUS to obtain 
     188 *   statistics from the frontend. 
     189 * 
     190 *   This is automatically called by MonitorLoop(), after Start() 
     191 *   has been used to start the signal monitoring thread. 
     192 */ 
     193void R5000SignalMonitor::UpdateValues(void) 
     194{ 
     195    if (!running || exit) 
     196        return; 
     197 
     198    if (dtvMonitorRunning) 
     199    { 
     200        EmitR5000Signals(); 
     201        if (IsAllGood()) 
     202            emit AllGood(); 
     203        // TODO dtv signals... 
     204 
     205        update_done = true; 
     206        return; 
     207    } 
     208 
     209    if (stb_needs_to_wait_for_power && 
     210        (stb_wait_for_power_timer.elapsed() < (int)kPowerTimeout)) 
     211    { 
     212        return; 
     213    } 
     214    stb_needs_to_wait_for_power = false; 
     215 
     216    R5000Channel *fwchan = dynamic_cast<R5000Channel*>(channel); 
     217 
     218    if (HasFlags(kFWSigMon_WaitForPower) && !HasFlags(kFWSigMon_PowerMatch)) 
     219    { 
     220        bool retried = false; 
     221        while (true) 
     222        { 
     223            R5000Device::PowerState power = fwchan->GetPowerState(); 
     224            if (R5000Device::kAVCPowerOn == power) 
     225            { 
     226                AddFlags(kFWSigMon_PowerSeen | kFWSigMon_PowerMatch); 
     227            } 
     228            else if (R5000Device::kAVCPowerOff == power) 
     229            { 
     230                AddFlags(kFWSigMon_PowerSeen); 
     231                fwchan->SetPowerState(true); 
     232                stb_wait_for_power_timer.start(); 
     233                stb_needs_to_wait_for_power = true; 
     234            } 
     235            else 
     236            { 
     237                bool qfailed = (R5000Device::kAVCPowerQueryFailed == power); 
     238                if (qfailed && !retried) 
     239                { 
     240                    retried = true; 
     241                    continue; 
     242                } 
     243 
     244                VERBOSE(VB_RECORD, "Can't determine if STB is power on, " 
     245                        "assuming it is..."); 
     246                AddFlags(kFWSigMon_PowerSeen | kFWSigMon_PowerMatch); 
     247            } 
     248            break; 
     249        } 
     250    } 
     251 
     252    bool isLocked = !HasFlags(kFWSigMon_WaitForPower) || 
     253        HasFlags(kFWSigMon_WaitForPower | kFWSigMon_PowerMatch); 
     254 
     255    if (isLocked && stb_needs_retune) 
     256    { 
     257        fwchan->Retune(); 
     258        isLocked = stb_needs_retune = false; 
     259    } 
     260 
     261    // Set SignalMonitorValues from info from card. 
     262    { 
     263        QMutexLocker locker(&statusLock); 
     264        signalStrength.SetValue(isLocked ? 100 : 0); 
     265        signalLock.SetValue(isLocked ? 1 : 0); 
     266    } 
     267 
     268    EmitR5000Signals(); 
     269    if (IsAllGood()) 
     270        emit AllGood(); 
     271 
     272    // Start table monitoring if we are waiting on any table 
     273    // and we have a lock. 
     274    if (isLocked && GetStreamData() && 
     275        HasAnyFlag(kDTVSigMon_WaitForPAT | kDTVSigMon_WaitForPMT | 
     276                   kDTVSigMon_WaitForMGT | kDTVSigMon_WaitForVCT | 
     277                   kDTVSigMon_WaitForNIT | kDTVSigMon_WaitForSDT)) 
     278    { 
     279        pthread_create(&table_monitor_thread, NULL, 
     280                       TableMonitorThread, this); 
     281 
     282        VERBOSE(VB_CHANNEL, LOC + "UpdateValues() -- " 
     283                "Waiting for table monitor to start"); 
     284 
     285        while (!dtvMonitorRunning) 
     286            usleep(50); 
     287 
     288        VERBOSE(VB_CHANNEL, LOC + "UpdateValues() -- " 
     289                "Table monitor started"); 
     290    } 
     291 
     292    update_done = true; 
     293} 
     294 
     295#define EMIT(SIGNAL_FUNC, SIGNAL_VAL) \ 
     296    do { statusLock.lock(); \ 
     297         SignalMonitorValue val = SIGNAL_VAL; \ 
     298         statusLock.unlock(); \ 
     299         emit SIGNAL_FUNC(val); } while (false) 
     300 
     301/** \fn R5000SignalMonitor::EmitR5000Signals(void) 
     302 *  \brief Emits signals for lock, signal strength, etc. 
     303 */ 
     304void R5000SignalMonitor::EmitR5000Signals(void) 
     305{ 
     306    // Emit signals.. 
     307    EMIT(StatusSignalLock, signalLock); 
     308    if (HasFlags(kDTVSigMon_WaitForSig)) 
     309        EMIT(StatusSignalStrength, signalStrength); 
     310} 
     311 
     312#undef EMIT 
  • new file libs/libmythtv/r5000channel.h

    - +  
     1/** 
     2 *  R5000Channel 
     3 *  Copyright (c) 2008 by Alan Nisota 
     4 *  Copyright (c) 2005 by Jim Westfall and Dave Abrahams 
     5 *  Distributed as part of MythTV under GPL v2 and later. 
     6 */ 
     7 
     8#ifndef _R5000CHANNEL_H_ 
     9#define _R5000CHANNEL_H_ 
     10 
     11#include "tv_rec.h" 
     12#include "dtvchannel.h" 
     13#include "r5000device.h" 
     14 
     15class R5000Channel : public DTVChannel 
     16{ 
     17  public: 
     18    R5000Channel(TVRec *parent, const QString &videodevice, 
     19                    const FireWireDBOptions &firewire_opts); 
     20    ~R5000Channel() { Close(); } 
     21 
     22    // Commands 
     23    virtual bool Open(void); 
     24    virtual void Close(void); 
     25 
     26    virtual bool TuneMultiplex(uint /*mplexid*/, QString /*inputname*/) 
     27        { return false; } 
     28    virtual bool Tune(const DTVMultiplex &/*tuning*/, QString /*inputname*/) 
     29        { return false; } 
     30    virtual bool Retune(void); 
     31 
     32    // Sets 
     33    virtual bool SetChannelByString(const QString &chan); 
     34    virtual bool SetChannelByNumber(int channel); 
     35    virtual bool SetPowerState(bool on); 
     36 
     37    // Gets 
     38    virtual bool IsOpen(void) const { return isopen; } 
     39    virtual R5000Device::PowerState GetPowerState(void) const; 
     40    virtual QString GetDevice(void) const; 
     41    virtual R5000Device *GetR5000Device(void) { return device; } 
     42 
     43  protected: 
     44    QString            videodevice; 
     45    FireWireDBOptions  fw_opts; 
     46    R5000Device    *device; 
     47    uint               current_channel; 
     48    bool               isopen; 
     49}; 
     50 
     51#endif // _FIREWIRECHANNEL_H_ 
  • new file libs/libmythtv/r5000device.h

    - +  
     1/** 
     2 *  R5000Device 
     3 *  Copyright (c) 2005 by Jim Westfall 
     4 *  Distributed as part of MythTV under GPL v2 and later. 
     5 */ 
     6 
     7#ifndef _R5000_DEVICE_H_ 
     8#define _R5000_DEVICE_H_ 
     9 
     10// C++ headers 
     11#include <vector> 
     12using namespace std; 
     13 
     14// Qt headers 
     15#include <qstring.h> 
     16#include <qmutex.h> 
     17 
     18// MythTV headers 
     19#include "streamlisteners.h" 
     20 
     21extern "C" { 
     22#include "r5000/r5000.h" 
     23} 
     24 
     25class TSPacket; 
     26class R5kPriv; 
     27class R5000Device 
     28{ 
     29  public: 
     30 
     31    // Public enums 
     32    typedef enum 
     33    { 
     34        kAVCPowerOn, 
     35        kAVCPowerOff, 
     36        kAVCPowerUnknown, 
     37        kAVCPowerQueryFailed, 
     38    } PowerState; 
     39 
     40    // AVC commands 
     41    typedef enum 
     42    { 
     43        kAVCControlCommand         = 0x00, 
     44        kAVCStatusInquiryCommand   = 0x01, 
     45        kAVCSpecificInquiryCommand = 0x02, 
     46        kAVCNotifyCommand          = 0x03, 
     47        kAVCGeneralInquiryCommand  = 0x04, 
     48 
     49        kAVCNotImplementedStatus   = 0x08, 
     50        kAVCAcceptedStatus         = 0x09, 
     51        kAVCRejectedStatus         = 0x0a, 
     52        kAVCInTransitionStatus     = 0x0b, 
     53        kAVCImplementedStatus      = 0x0c, 
     54        kAVCChangedStatus          = 0x0d, 
     55 
     56        kAVCInterimStatus          = 0x0f, 
     57        kAVCResponseImplemented    = 0x0c, 
     58    } IEEE1394Command; 
     59 
     60    // AVC unit addresses 
     61    typedef enum 
     62    { 
     63        kAVCSubunitId0                = 0x00, 
     64        kAVCSubunitId1                = 0x01, 
     65        kAVCSubunitId2                = 0x02, 
     66        kAVCSubunitId3                = 0x03, 
     67        kAVCSubunitId4                = 0x04, 
     68        kAVCSubunitIdExtended         = 0x05, 
     69        kAVCSubunitIdIgnore           = 0x07, 
     70 
     71        kAVCSubunitTypeVideoMonitor   = (0x00 << 3), 
     72        kAVCSubunitTypeAudio          = (0x01 << 3), 
     73        kAVCSubunitTypePrinter        = (0x02 << 3), 
     74        kAVCSubunitTypeDiscRecorder   = (0x03 << 3), 
     75        kAVCSubunitTypeTapeRecorder   = (0x04 << 3), 
     76        kAVCSubunitTypeTuner          = (0x05 << 3), 
     77        kAVCSubunitTypeCA             = (0x06 << 3), 
     78        kAVCSubunitTypeVideoCamera    = (0x07 << 3), 
     79        kAVCSubunitTypePanel          = (0x09 << 3), 
     80        kAVCSubunitTypeBulletinBoard  = (0x0a << 3), 
     81        kAVCSubunitTypeCameraStorage  = (0x0b << 3), 
     82        kAVCSubunitTypeMusic          = (0x0c << 3), 
     83        kAVCSubunitTypeVendorUnique   = (0x1c << 3), 
     84        kAVCSubunitTypeExtended       = (0x1e << 3), 
     85        kAVCSubunitTypeUnit           = (0x1f << 3), 
     86    } IEEE1394UnitAddress; 
     87 
     88    // AVC opcode 
     89    typedef enum 
     90    { 
     91        // Unit 
     92        kAVCUnitPlugInfoOpcode               = 0x02, 
     93        kAVCUnitDigitalOutputOpcode          = 0x10, 
     94        kAVCUnitDigitalInputOpcode           = 0x11, 
     95        kAVCUnitChannelUsageOpcode           = 0x12, 
     96        kAVCUnitOutputPlugSignalFormatOpcode = 0x18, 
     97        kAVCUnitInputPlugSignalFormatOpcode  = 0x19, 
     98        kAVCUnitConnectAVOpcode              = 0x20, 
     99        kAVCUnitDisconnectAVOpcode           = 0x21, 
     100        kAVCUnitConnectionsOpcode            = 0x22, 
     101        kAVCUnitConnectOpcode                = 0x24, 
     102        kAVCUnitDisconnectOpcode             = 0x25, 
     103        kAVCUnitUnitInfoOpcode               = 0x30, 
     104        kAVCUnitSubunitInfoOpcode            = 0x31, 
     105        kAVCUnitSignalSourceOpcode           = 0x1a, 
     106        kAVCUnitPowerOpcode                  = 0xb2, 
     107 
     108        // Common Unit + Subunit 
     109        kAVCCommonOpenDescriptorOpcode       = 0x08, 
     110        kAVCCommonReadDescriptorOpcode       = 0x09, 
     111        kAVCCommonWriteDescriptorOpcode      = 0x0A, 
     112        kAVCCommonSearchDescriptorOpcode     = 0x0B, 
     113        kAVCCommonObjectNumberSelectOpcode   = 0x0D, 
     114        kAVCCommonPowerOpcode                = 0xB2, 
     115        kAVCCommonReserveOpcode              = 0x01, 
     116        kAVCCommonPlugInfoOpcode             = 0x02, 
     117        kAVCCommonVendorDependentOpcode      = 0x00, 
     118 
     119        // Panel 
     120        kAVCPanelPassThrough                 = 0x7c, 
     121    } IEEE1394Opcode; 
     122 
     123    // AVC param 0 
     124    typedef enum 
     125    { 
     126        kAVCPowerStateOn           = 0x70, 
     127        kAVCPowerStateOff          = 0x60, 
     128        kAVCPowerStateQuery        = 0x7f, 
     129    } IEEE1394UnitPowerParam0; 
     130 
     131    typedef enum 
     132    { 
     133        kAVCPanelKeySelect          = 0x00, 
     134        kAVCPanelKeyUp              = 0x01, 
     135        kAVCPanelKeyDown            = 0x02, 
     136        kAVCPanelKeyLeft            = 0x03, 
     137        kAVCPanelKeyRight           = 0x04, 
     138        kAVCPanelKeyRightUp         = 0x05, 
     139        kAVCPanelKeyRightDown       = 0x06, 
     140        kAVCPanelKeyLeftUp          = 0x07, 
     141        kAVCPanelKeyLeftDown        = 0x08, 
     142        kAVCPanelKeyRootMenu        = 0x09, 
     143        kAVCPanelKeySetupMenu       = 0x0A, 
     144        kAVCPanelKeyContentsMenu    = 0x0B, 
     145        kAVCPanelKeyFavoriteMenu    = 0x0C, 
     146        kAVCPanelKeyExit            = 0x0D, 
     147 
     148        kAVCPanelKey0               = 0x20, 
     149        kAVCPanelKey1               = 0x21, 
     150        kAVCPanelKey2               = 0x22, 
     151        kAVCPanelKey3               = 0x23, 
     152        kAVCPanelKey4               = 0x24, 
     153        kAVCPanelKey5               = 0x25, 
     154        kAVCPanelKey6               = 0x26, 
     155        kAVCPanelKey7               = 0x27, 
     156        kAVCPanelKey8               = 0x28, 
     157        kAVCPanelKey9               = 0x29, 
     158        kAVCPanelKeyDot             = 0x2A, 
     159        kAVCPanelKeyEnter           = 0x2B, 
     160        kAVCPanelKeyClear           = 0x2C, 
     161 
     162        kAVCPanelKeyChannelUp       = 0x30, 
     163        kAVCPanelKeyChannelDown     = 0x31, 
     164        kAVCPanelKeyPreviousChannel = 0x32, 
     165        kAVCPanelKeySoundSelect     = 0x33, 
     166        kAVCPanelKeyInputSelect     = 0x34, 
     167        kAVCPanelKeyDisplayInfo     = 0x35, 
     168        kAVCPanelKeyHelp            = 0x36, 
     169        kAVCPanelKeyPageUp          = 0x37, 
     170        kAVCPanelKeyPageDown        = 0x38, 
     171 
     172        kAVCPanelKeyPower           = 0x40, 
     173        kAVCPanelKeyVolumeUp        = 0x41, 
     174        kAVCPanelKeyVolumeDown      = 0x42, 
     175        kAVCPanelKeyMute            = 0x43, 
     176        kAVCPanelKeyPlay            = 0x44, 
     177        kAVCPanelKeyStop            = 0x45, 
     178        kAVCPanelKeyPause           = 0x46, 
     179        kAVCPanelKeyRecord          = 0x47, 
     180        kAVCPanelKeyRewind          = 0x48, 
     181        kAVCPanelKeyFastForward     = 0x49, 
     182        kAVCPanelKeyEject           = 0x4a, 
     183        kAVCPanelKeyForward         = 0x4b, 
     184        kAVCPanelKeyBackward        = 0x4c, 
     185 
     186        kAVCPanelKeyAngle           = 0x50, 
     187        kAVCPanelKeySubPicture      = 0x51, 
     188 
     189        kAVCPanelKeyTuneFunction    = 0x67, 
     190 
     191        kAVCPanelKeyPress           = 0x00, 
     192        kAVCPanelKeyRelease         = 0x80, 
     193 
     194    } IEEE1394PanelPassThroughParam0; 
     195 
     196    R5000Device(uint64_t guid, uint subunitid, uint speed); 
     197    ~R5000Device(); 
     198 
     199    bool OpenPort(void); 
     200    bool ClosePort(void); 
     201    void RunPortHandler(void); 
     202 
     203    // Commands 
     204    virtual bool ResetBus(void) { return false; } 
     205 
     206    virtual void AddListener(TSDataListener*); 
     207    virtual void RemoveListener(TSDataListener*); 
     208 
     209    // Sets 
     210    virtual bool SetPowerState(bool on); 
     211    virtual bool SetChannel(const QString &panel_model, 
     212                            uint alt_method, uint channel); 
     213 
     214    // Gets 
     215    bool IsSTBBufferCleared(void) const { return m_buffer_cleared; } 
     216 
     217    // non-const Gets 
     218    virtual PowerState GetPowerState(void); 
     219 
     220    // Statics 
     221    static bool IsSTBSupported(const QString &model); 
     222    static QString GetModelName(uint vendorid, uint modelid); 
     223    void BroadcastToListeners( 
     224        const unsigned char *data, uint dataSize); 
     225 
     226  protected: 
     227 
     228    bool GetSubunitInfo(uint8_t table[32]); 
     229 
     230    void SetLastChannel(uint channel); 
     231    void ProcessPATPacket(const TSPacket&); 
     232    bool StartStreaming(void); 
     233    bool StopStreaming(void); 
     234 
     235    uint64_t                 m_guid; 
     236    uint                     m_subunitid; 
     237    uint                     m_speed; 
     238    uint                     m_last_channel; 
     239    uint                     m_last_crc; 
     240    bool                     m_buffer_cleared; 
     241 
     242    uint                     m_open_port_cnt; 
     243    vector<TSDataListener*>  m_listeners; 
     244    mutable QMutex           m_lock; 
     245 
     246    /// Vendor ID + Model ID to R5000Device STB model string 
     247    static QMap<uint64_t,QString> s_id_to_model; 
     248    static QMutex                 s_static_lock; 
     249private: 
     250    r5kdev_t                 *usbdev; 
     251    R5kPriv                  *m_priv; 
     252}; 
     253 
     254#endif // _FIREWIRE_DEVICE_H_ 
  • new file libs/libmythtv/r5000recorder.h

    - +  
     1/** 
     2 *  R5000Recorder 
     3 *  Copyright (c) 2005 by Jim Westfall 
     4 *  Distributed as part of MythTV under GPL v2 and later. 
     5 */ 
     6 
     7#ifndef _R5000RECORDER_H_ 
     8#define _R5000RECORDER_H_ 
     9 
     10// MythTV headers 
     11#include "dtvrecorder.h" 
     12#include "tspacket.h" 
     13#include "streamlisteners.h" 
     14 
     15class TVRec; 
     16class R5000Channel; 
     17 
     18/** \class R5000Recorder 
     19 *  \brief This is a specialization of DTVRecorder used to 
     20 *         handle DVB and ATSC streams from a firewire input. 
     21 * 
     22 *  \sa DTVRecorder 
     23 */ 
     24class R5000Recorder : public DTVRecorder, 
     25                         public MPEGSingleProgramStreamListener, 
     26                         public TSDataListener 
     27{ 
     28    friend class MPEGStreamData; 
     29    friend class TSPacketProcessor; 
     30 
     31  public: 
     32    R5000Recorder(TVRec *rec, R5000Channel *chan); 
     33    virtual ~R5000Recorder(); 
     34 
     35    // Commands 
     36    bool Open(void); 
     37    void Close(void); 
     38 
     39    void StartStreaming(void); 
     40    void StopStreaming(void); 
     41 
     42    void StartRecording(void); 
     43    bool PauseAndWait(int timeout = 100); 
     44 
     45    void AddData(const unsigned char *data, uint dataSize); 
     46    void ProcessTSPacket(const TSPacket &tspacket); 
     47 
     48    // Sets 
     49    void SetOptionsFromProfile(RecordingProfile *profile, 
     50                               const QString &videodev, 
     51                               const QString &audiodev, 
     52                               const QString &vbidev); 
     53    void SetStreamData(MPEGStreamData*); 
     54 
     55    // Gets 
     56    MPEGStreamData *GetStreamData(void) { return _mpeg_stream_data; } 
     57 
     58    // MPEG Single Program 
     59    void HandleSingleProgramPAT(ProgramAssociationTable*); 
     60    void HandleSingleProgramPMT(ProgramMapTable*); 
     61 
     62  protected: 
     63    R5000Recorder(TVRec *rec); 
     64 
     65  private: 
     66    MPEGStreamData        *_mpeg_stream_data; 
     67    R5000Channel       *channel; 
     68    bool                   isopen; 
     69    vector<unsigned char>  buffer; 
     70}; 
     71 
     72#endif //  _R5000RECORDER_H_ 
  • new file libs/libmythtv/r5000signalmonitor.h

    - +  
     1// -*- Mode: c++ -*- 
     2 
     3#ifndef _R5000SIGNALMONITOR_H_ 
     4#define _R5000SIGNALMONITOR_H_ 
     5 
     6#include <qmap.h> 
     7#include <qmutex.h> 
     8#include <qdatetime.h> 
     9 
     10#include "dtvsignalmonitor.h" 
     11#include "firewiredevice.h" 
     12#include "util.h" 
     13 
     14class R5000Channel; 
     15 
     16class R5000SignalMonitor : public DTVSignalMonitor, public TSDataListener 
     17{ 
     18    Q_OBJECT 
     19 
     20  public: 
     21    R5000SignalMonitor(int db_cardnum, R5000Channel *_channel, 
     22                          uint64_t _flags = kFWSigMon_WaitForPower, 
     23                          const char *_name = "R5000SignalMonitor"); 
     24 
     25    virtual void HandlePAT(const ProgramAssociationTable*); 
     26    virtual void HandlePMT(uint, const ProgramMapTable*); 
     27 
     28    void Stop(void); 
     29 
     30  public slots: 
     31    void deleteLater(void); 
     32 
     33  protected: 
     34    R5000SignalMonitor(void); 
     35    R5000SignalMonitor(const R5000SignalMonitor&); 
     36    virtual ~R5000SignalMonitor(); 
     37 
     38    virtual void UpdateValues(void); 
     39    void EmitR5000Signals(void); 
     40 
     41    static void *TableMonitorThread(void *param); 
     42    void RunTableMonitor(void); 
     43 
     44    bool SupportsTSMonitoring(void); 
     45 
     46    void AddData(const unsigned char *data, uint dataSize); 
     47 
     48  public: 
     49    static const uint kPowerTimeout; 
     50    static const uint kBufferTimeout; 
     51 
     52  protected: 
     53    bool               dtvMonitorRunning; 
     54    pthread_t          table_monitor_thread; 
     55    bool               stb_needs_retune; 
     56    bool               stb_needs_to_wait_for_pat; 
     57    bool               stb_needs_to_wait_for_power; 
     58    MythTimer          stb_wait_for_pat_timer; 
     59    MythTimer          stb_wait_for_power_timer; 
     60 
     61    vector<unsigned char> buffer; 
     62 
     63    static QMap<void*,uint> pat_keys; 
     64    static QMutex           pat_keys_lock; 
     65}; 
     66 
     67#endif // _R5000SIGNALMONITOR_H_ 
  • new file libs/libmythtv/r5000/libusb_augment.c

    - +  
     1// 2005-10-19/lindi: downloaded from http://www.gaesi.org/~nmct/cvista/cvista/ 
     2 
     3// libusb_augment.c 
     4// $Revision$ 
     5// $Date$ 
     6 
     7// Hopefully, the functions in this file will become part of libusb. 
     8 
     9#include <stdio.h> 
     10#include <sys/ioctl.h> 
     11#include <errno.h> 
     12#include <sys/time.h> 
     13#include <sys/poll.h> 
     14#include <usb.h> 
     15#include <linux/usbdevice_fs.h> 
     16#include <string.h> 
     17#include <signal.h> 
     18#define LIBUSB_AUGMENT 
     19#include "libusb_augment.h" 
     20 
     21// Taken from libusb file usbi.h because usb.h 
     22// hides the definition of usb_dev_handle. 
     23extern int usb_debug; 
     24 
     25struct usb_dev_handle { 
     26  int fd; 
     27 
     28  struct usb_bus *bus; 
     29  struct usb_device *device; 
     30 
     31  int config; 
     32  int interface; 
     33  int altsetting; 
     34 
     35  /* Added by RMT so implementations can store other per-open-device data */ 
     36  void *impl_info; 
     37}; 
     38 
     39// Taken from libusb file error.h to supply error handling macro definition. 
     40typedef enum { 
     41  USB_ERROR_TYPE_NONE = 0, 
     42  USB_ERROR_TYPE_STRING, 
     43  USB_ERROR_TYPE_ERRNO, 
     44} usb_error_type_t; 
     45 
     46extern char usb_error_str[1024]; 
     47extern usb_error_type_t usb_error_type; 
     48 
     49#define USB_ERROR_STR(format, args...) \ 
     50        do { \ 
     51          usb_error_type = USB_ERROR_TYPE_STRING; \ 
     52          snprintf(usb_error_str, sizeof(usb_error_str) - 1, format, ## args); \ 
     53          if (usb_debug >= 2) \ 
     54            fprintf(stderr, "USB error: %s\n", usb_error_str); \ 
     55        } while (0) 
     56 
     57static int urb_signr = 0; 
     58void (*urb_completion_callback)(struct usbdevfs_urb *) = NULL; 
     59#define USB_ASYNC_COMPLETION_SIGNAL (SIGRTMIN + 5) 
     60 
     61void urb_completion_handler(int signum, siginfo_t *info, void *context) 
     62{ 
     63   struct usbdevfs_urb *urb = (struct usbdevfs_urb *)info->si_addr; 
     64   struct usbdevfs_urb *context1; 
     65   usb_dev_handle *dev = (usb_dev_handle *)urb->usercontext; 
     66   int ret; 
     67   if (info->si_code != SI_ASYNCIO || 
     68       info->si_signo != USB_ASYNC_COMPLETION_SIGNAL) { 
     69       return; 
     70   } 
     71   if(info->si_errno != 0) { 
     72     USB_ERROR_STR("Async URB Completion failed: %s", strerror(info->si_errno)); 
     73     return; 
     74   } 
     75   ret = ioctl(dev->fd, USBDEVFS_REAPURB, &context1); 
     76   if(ret  < 0) { 
     77     USB_ERROR_STR("Failed to read URB: %s", strerror(-ret)); 
     78     return; 
     79   } 
     80   if(context1 != urb) { 
     81     USB_ERROR_STR("Reaped unexpected urb"); 
     82     return; 
     83   } 
     84   if(urb_completion_callback) 
     85     urb_completion_callback(urb); 
     86} 
     87 
     88int usbdevfs_urb_signal_completion(void (*cb)( struct usbdevfs_urb *)) 
     89{ 
     90  urb_completion_callback = cb; 
     91  urb_signr = USB_ASYNC_COMPLETION_SIGNAL; 
     92  struct sigaction usb_linux_sa; 
     93  usb_linux_sa.sa_sigaction = urb_completion_handler; 
     94  sigfillset(&usb_linux_sa.sa_mask); 
     95  usb_linux_sa.sa_flags = SA_SIGINFO; 
     96  usb_linux_sa.sa_flags |= SA_ONSTACK; 
     97  sigaction(USB_ASYNC_COMPLETION_SIGNAL, &usb_linux_sa, NULL); 
     98  return 0; 
     99} 
     100 
     101struct usbdevfs_urb *usb_bulk_setup( 
     102                struct usbdevfs_urb *iso_urb, // URB pointer-pointer. 
     103                unsigned char ep,  // Device endpoint. 
     104                char *bytes,       // Data buffer pointer. 
     105                int size) {        // Size of the buffer. 
     106  struct usbdevfs_urb *local_urb; 
     107 
     108  // No more than 16384 bytes can be transferred at a time. 
     109  if (size > 16384) { 
     110    USB_ERROR_STR("error on transfer size: %s", strerror(EINVAL)); 
     111    return NULL; 
     112  } 
     113  local_urb = iso_urb; 
     114  if (!local_urb) { 
     115    local_urb = (struct usbdevfs_urb *) calloc(1, sizeof(struct usbdevfs_urb)); 
     116    if (!local_urb) { 
     117      USB_ERROR_STR("error on packet size: %s", strerror(EINVAL)); 
     118      return NULL; 
     119    } 
     120  } 
     121  local_urb->type = USBDEVFS_URB_TYPE_BULK; 
     122  local_urb->endpoint = ep; 
     123  local_urb->status = 0; 
     124  local_urb->flags = 0; 
     125  local_urb->buffer = bytes; 
     126  local_urb->buffer_length = size; 
     127  local_urb->actual_length = 0; 
     128  local_urb->start_frame = 0; 
     129  local_urb->number_of_packets = 0; 
     130  local_urb->error_count = 0; 
     131  local_urb->signr = urb_signr; 
     132  local_urb->usercontext = (void *) 0; 
     133  return local_urb; 
     134} 
     135// Reading and writing are the same except for the endpoint 
     136int usb_isochronous_setup(struct usbdevfs_urb **iso_urb, // URB pointer-pointer. 
     137                          unsigned char ep,  // Device endpoint. 
     138                          int pktsize,       // Endpoint packet size. 
     139                          char *bytes,       // Data buffer pointer. 
     140                          int size) {        // Size of the buffer. 
     141  struct usbdevfs_urb *local_urb; 
     142  // int ret 
     143  // was unused /lindi 
     144  int pktcount, fullpkts, partpktsize, packets, urb_size; 
     145 
     146  // No more than 32768 bytes can be transferred at a time. 
     147  if (size > 32768) { 
     148    USB_ERROR_STR("error on transfer size: %s", strerror(EINVAL)); 
     149    return -EINVAL; 
     150  } 
     151 
     152  // Determine the number of packets that need to be created based upon the 
     153  // amount of data to be transferred, and the maximum packet size of the 
     154  // endpoint. 
     155 
     156  // Find integral number of full packets. 
     157  //fprintf(stderr, "buf size: %d\n", size); 
     158  //fprintf(stderr, "iso size: %d\n", pktsize); 
     159  fullpkts = size / pktsize; 
     160  //fprintf(stderr, "Number of full packets: %d\n", fullpkts); 
     161  // Find length of partial packet. 
     162  partpktsize = size % pktsize; 
     163  //fprintf(stderr, "Size of partial packet: %d\n", partpktsize); 
     164  // Find total number of packets to be transfered. 
     165  packets = fullpkts + ((partpktsize > 0) ? 1 : 0); 
     166  //fprintf(stderr, "Total number of packets: %d\n", packets); 
     167  // Limit the number of packets transfered according to 
     168  // the Linux usbdevfs maximum read/write buffer size. 
     169  if ((packets < 1) || (packets > 128)) { 
     170    USB_ERROR_STR("error on packet size: %s", strerror(EINVAL)); 
     171    return -EINVAL; 
     172  } 
     173 
     174  // If necessary, allocate the urb and packet 
     175  // descriptor structures from the heap. 
     176  local_urb = *iso_urb; 
     177  if (!local_urb) { 
     178    urb_size = sizeof(struct usbdevfs_urb) + 
     179      packets * sizeof(struct usb_iso_packet_desc); 
     180    local_urb = (struct usbdevfs_urb *) calloc(1, urb_size); 
     181    if (!local_urb) { 
     182      USB_ERROR_STR("error on packet size: %s", strerror(EINVAL)); 
     183      return -ENOMEM; 
     184    } 
     185  } 
     186 
     187  // Set up each packet for the data to be transferred. 
     188  for (pktcount = 0; pktcount < fullpkts; pktcount++) { 
     189    local_urb->iso_frame_desc[pktcount].length = pktsize; 
     190    local_urb->iso_frame_desc[pktcount].actual_length = 0; 
     191    local_urb->iso_frame_desc[pktcount].status = 0; 
     192  } 
     193 
     194  // Set up the last packet for the partial data to be transferred. 
     195  if (partpktsize > 0) { 
     196    local_urb->iso_frame_desc[pktcount].length = partpktsize; 
     197    local_urb->iso_frame_desc[pktcount].actual_length = 0; 
     198    local_urb->iso_frame_desc[pktcount++].status = 0; 
     199  } 
     200 
     201  // Set up the URB structure. 
     202  local_urb->type = USBDEVFS_URB_TYPE_ISO; 
     203  //fprintf(stderr, "type: %d\n", local_urb->type); 
     204  local_urb->endpoint = ep; 
     205  //fprintf(stderr, "endpoint: 0x%x\n", local_urb->endpoint); 
     206  local_urb->status = 0; 
     207  local_urb->flags = USBDEVFS_URB_ISO_ASAP; // Additional flags here? 
     208  //fprintf(stderr, "flags: %d\n", local_urb->flags); 
     209  local_urb->buffer = bytes; 
     210  //fprintf(stderr, "buffer: 0x%x\n", local_urb->buffer); 
     211  local_urb->buffer_length = size; 
     212  //fprintf(stderr, "buffer_length: %d\n", local_urb->buffer_length); 
     213  local_urb->actual_length = 0; 
     214  local_urb->start_frame = 0; 
     215  //fprintf(stderr, "start_frame: %d\n", local_urb->start_frame); 
     216  local_urb->number_of_packets = pktcount; 
     217  //fprintf(stderr, "number_of_packets: %d\n", local_urb->number_of_packets); 
     218  local_urb->error_count = 0; 
     219  local_urb->signr = 0; 
     220  //fprintf(stderr, "signr: %d\n", local_urb->signr); 
     221  local_urb->usercontext = (void *) 0; 
     222  *iso_urb = local_urb; 
     223  return 0; 
     224} 
     225 
     226 
     227int usb_urb_submit(usb_dev_handle *dev,     // Open usb device handle. 
     228                   struct usbdevfs_urb *iso_urb,        // Pointer to URB. 
     229                   struct timeval *tv_submit) { // Time structure pointer. 
     230  int ret; 
     231 
     232  iso_urb->usercontext = dev; 
     233  // Get actual time, of the URB submission. 
     234  if(tv_submit) 
     235    gettimeofday(tv_submit, NULL); 
     236  // Submit the URB through an IOCTL call. 
     237  ret = ioctl(dev->fd, USBDEVFS_SUBMITURB, iso_urb); 
     238  //fprintf(stderr, "start_frame now: %d\n", iso_urb->start_frame); 
     239  //fprintf(stderr, "submit ioctl return value: %d\n", ret); 
     240  if (ret < 0) { 
     241    //fprintf(stderr, "error submitting URB: %s\n", strerror(errno)); 
     242    USB_ERROR_STR("error submitting URB: %s", strerror(errno)); 
     243    return -errno; 
     244  } 
     245  return ret; 
     246} 
     247 
     248 
     249int usb_urb_reap(usb_dev_handle *dev,     // Open usb device handle. 
     250                 struct usbdevfs_urb *iso_urb,        // Pointer to URB. 
     251                 int timeout) {           // Attempt timeout (usec). 
     252  struct timeval tv_ref, tv_msec, tv; 
     253  void *context; 
     254  int waiting, ret; 
     255  struct pollfd ufd[1]; 
     256 
     257  // Get actual time, and add the timeout value. The result is the absolute 
     258  // time where we have to quit waiting for an isochronous message. 
     259  ufd[0].fd = dev->fd; 
     260  ufd[0].events = POLLIN | POLLOUT; 
     261  ufd[0].revents = 0; 
     262  ret = poll(ufd, 1, timeout); 
     263  if(ret <= 0) 
     264    return -ETIMEDOUT; 
     265 
     266  //fprintf(stderr, "preparing to reap\n"); 
     267  ret = ioctl(dev->fd, USBDEVFS_REAPURB, &context); 
     268 
     269  /* 
     270   * If there was an error, that wasn"t EAGAIN (no completion), then 
     271   * something happened during the reaping and we should return that 
     272   * error now 
     273   */ 
     274  //fprintf(stderr, "reap ioctl return value: %d\n", ret); 
     275  if (ret < 0) { 
     276    USB_ERROR_STR("error reaping interrupt URB: %s", 
     277                  strerror(errno)); 
     278    return -errno; 
     279  } 
     280 
     281  //fprintf(stderr, "actual_length: %d\n", iso_urb->actual_length); 
     282  //fprintf(stderr, "URB status: %d\n", iso_urb->status); 
     283  //fprintf(stderr, "error count: %d\n", iso_urb->error_count); 
     284 
     285  //fprintf(stderr, "waiting done\n"); 
     286  if(iso_urb != context) { 
     287    fprintf(stderr, "Expected urb: %p but got %p\n", iso_urb, context); 
     288    return -1; 
     289  } 
     290  //fprintf(stderr, "Total bytes: %d\n", bytesdone); 
     291  return iso_urb->actual_length; 
     292} 
     293 
     294int usb_urb_cancel(usb_dev_handle *dev, struct usbdevfs_urb *iso_urb) 
     295{ 
     296  return ioctl(dev->fd, USBDEVFS_DISCARDURB, iso_urb); 
     297} 
  • new file libs/libmythtv/r5000/libusb_augment.h

    - +  
     1// libusb_augment.h 
     2// $Revision$ 
     3// $Date$ 
     4 
     5#ifdef LIBUSB_AUGMENT 
     6// Taken from libusb file linux.h to provide the URB structure definitions. 
     7struct usb_iso_packet_desc { 
     8  unsigned int length; 
     9  unsigned int actual_length; 
     10  unsigned int status; 
     11}; 
     12#endif 
     13 
     14int usbdevfs_urb_signal_completion(void (*cb)( struct usbdevfs_urb *)); 
     15struct usbdevfs_urb *usb_bulk_setup(struct usbdevfs_urb *iso_urb, unsigned char ep, 
     16                   char *bytes, int size); 
     17int usb_isochronous_setup(struct usbdevfs_urb **iso_urb, unsigned char ep, 
     18                          int pktsize, char *bytes, int size); 
     19int usb_urb_submit(usb_dev_handle *dev, struct usbdevfs_urb *iso_urb, 
     20                   struct timeval *tv_rsubmit); 
     21int usb_urb_reap(usb_dev_handle *dev, struct usbdevfs_urb *iso_urb, 
     22                 int timeout_usec); 
     23int usb_urb_cancel(usb_dev_handle *dev, struct usbdevfs_urb *iso_urb); 
  • new file libs/libmythtv/r5000/r5000.c

    - +  
     1//#define R5K_DEBUG 
     2#include <stdio.h> 
     3#include <sys/types.h> 
     4#include <sys/stat.h> 
     5#include <fcntl.h> 
     6#include <string.h> 
     7#include <errno.h> 
     8 
     9       #include <sys/time.h> 
     10       #include <time.h> 
     11 
     12 
     13#include <usb.h> 
     14#include <linux/usbdevice_fs.h> 
     15#include "libusb_augment.h" 
     16#include "r5000buttons.h" 
     17 
     18#define MAX_URBS_IN_FLIGHT 128 
     19#define R5K_URB_BUFFER_SIZE (1 << 14) 
     20#define R5K_MAX_PIDS 10 
     21 
     22typedef struct { 
     23  usb_dev_handle *handle; 
     24  struct usbdevfs_urb *urbs; 
     25  unsigned char *buffer; 
     26  unsigned char leftover[188]; 
     27  unsigned int (*cb)(unsigned char *buffer, int len, void *callback_data); 
     28  void *cb_data; 
     29  int nexturb; 
     30  int streaming; 
     31  int offset; 
     32  int realtime; 
     33  int bytes_read; 
     34#ifdef R5K_DEBUG 
     35  int fd; 
     36#endif 
     37  unsigned char pmt_pkt[188]; 
     38  unsigned char num_pmt_entries; 
     39  unsigned char pmt_state; 
     40  unsigned char pmt_next_cc; 
     41  struct { 
     42    int pid; 
     43    unsigned char id; 
     44  } pmt[R5K_MAX_PIDS]; 
     45} r5kdev_t; 
     46 
     47static r5kdev_t *glbl_r5kdev; 
     48static int r5000_usb_init = 0; 
     49static unsigned char r5000_pat_pkt[188] = { 
     500x47, 0x40, 0x00, 0x13, 0x00, 0x00, 0xb0, 0x0d, 0x00, 0x06, 0xc5, 0x00, 0x00, 0x00, 0x01, 0xe0, 
     510x21, 0x19, 0x3a, 0x82, 0xc4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
     520xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
     530xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
     540xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
     550xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
     560xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
     570xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
     580xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
     590xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
     600xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
     610xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 
     62enum { 
     63  R5K_PMT_START = 0x01, 
     64  R5K_PMT_READY = 0x02 
     65}; 
     66static int r5000_pmt_state = 0; 
     67static unsigned char r5000_pmt[188]; 
     68static int r5000_pmt_count = 0; 
     69static unsigned char r5000_pmt_partial[188*20]; 
     70static int r5000_pmt_partial_count = 0; 
     71static int r5000_pmt_cc; 
     72static void r5000_process_urb(struct usbdevfs_urb *urb); 
     73 
     74int r5000_create_urbs(r5kdev_t *r5kdev) 
     75{ 
     76  int i; 
     77  r5kdev->urbs = (struct usbdevfs_urb *)malloc(sizeof(struct usbdevfs_urb) * MAX_URBS_IN_FLIGHT); 
     78  r5kdev->buffer = malloc(R5K_URB_BUFFER_SIZE * MAX_URBS_IN_FLIGHT); 
     79  for(i = 0; i < MAX_URBS_IN_FLIGHT; i++) { 
     80    usb_bulk_setup(&r5kdev->urbs[i], 0x82, r5kdev->buffer + (R5K_URB_BUFFER_SIZE*i), R5K_URB_BUFFER_SIZE); 
     81  } 
     82  r5kdev->nexturb = 0; 
     83  return 0; 
     84} 
     85 
     86int r5000_free_urbs(r5kdev_t *r5kdev) 
     87{ 
     88  free(r5kdev->urbs); 
     89  free(r5kdev->buffer); 
     90  return 0; 
     91} 
     92 
     93usb_dev_handle *r5000_locate_device( 
     94    unsigned short vendor_id, unsigned short product_id) 
     95{ 
     96  struct usb_bus *bus; 
     97  struct usb_device *dev; 
     98  usb_dev_handle *device_handle = 0; 
     99  usb_find_busses(); 
     100  usb_find_devices(); 
     101 
     102   for (bus = usb_get_busses(); bus; bus = bus->next) 
     103  { 
     104    for (dev = bus->devices; dev; dev = dev->next) 
     105    { 
     106      if (dev->descriptor.idVendor == vendor_id && 
     107          dev->descriptor.idProduct == product_id) 
     108      { 
     109        device_handle = usb_open(dev); 
     110        printf("XSV Device Found @ Address %s \n", dev->filename); 
     111        printf("XSV Vendor ID 0x0%x\n",dev->descriptor.idVendor); 
     112        printf("XSV Product ID 0x0%x\n",dev->descriptor.idProduct); 
     113      } 
     114    } 
     115  } 
     116 
     117  if (device_handle==0) return (0); 
     118  int open_status = usb_set_configuration(device_handle,1); 
     119  printf("conf_stat=%d\n",open_status); 
     120 
     121  open_status = usb_claim_interface(device_handle,0); 
     122  printf("claim_stat=%d\n",open_status); 
     123 
     124  open_status = usb_set_altinterface(device_handle,0); 
     125  printf("alt_stat=%d\n",open_status); 
     126  return (device_handle); 
     127} 
     128 
     129int r5000_start_stream(r5kdev_t *r5kdev) 
     130{ 
     131  unsigned char data[0x80]; 
     132  int bytes; 
     133  int i; 
     134  struct usb_dev_handle *handle = (struct usb_dev_handle *)r5kdev->handle; 
     135 
     136  if(! r5kdev->urbs) 
     137    r5000_create_urbs(r5kdev); 
     138/* 
     139  data[0] = 0x20; 
     140  usb_bulk_write(handle, 1, data, 1, 5000); 
     141 
     142  bytes = usb_bulk_read(handle, 129, data, 4, 5000); 
     143  bytes = usb_bulk_read(handle, 129, data, 128, 5000); 
     144*/ 
     145  data[0] = 0x30; 
     146  usb_bulk_write(handle, 1, data, 1, 5000); 
     147  bytes = usb_bulk_read(handle, 129, data, 2, 5000); 
     148 
     149  data[0] = 0x50; 
     150  usb_bulk_write(handle, 1, data, 1, 5000); 
     151 
     152  for(i=0; i < MAX_URBS_IN_FLIGHT; i++) { 
     153    usb_urb_submit(handle, &r5kdev->urbs[i], NULL); 
     154  } 
     155  r5kdev->nexturb = 0; 
     156  r5kdev->streaming = 1; 
     157  r5kdev->offset = 0; 
     158  return 1; 
     159} 
     160 
     161int r5000_stop_stream(r5kdev_t *r5kdev) 
     162{ 
     163  struct usb_dev_handle *handle = (struct usb_dev_handle *)r5kdev->handle; 
     164  struct usbdevfs_urb *urbs = (struct usbdevfs_urb *)r5kdev->urbs; 
     165  int i; 
     166 
     167  if(r5kdev->streaming) { 
     168    for(i=0; i < MAX_URBS_IN_FLIGHT; i++) 
     169      usb_urb_cancel(handle, &urbs[i]); 
     170    r5kdev->streaming = 0; 
     171  } 
     172  return 0; 
     173} 
     174 
     175r5kdev_t *r5000_open(unsigned int (*cb)(unsigned char *buffer, int len, void *callback_data), void *cb_data, int realtime) 
     176{ 
     177  r5kdev_t *r5kdev; 
     178  struct usb_dev_handle *handle; 
     179  if(! r5000_usb_init) { 
     180    usb_init(); 
     181    r5000_usb_init = 1; 
     182  } 
     183  handle = r5000_locate_device(0x0547, 0x1002); 
     184  if(! handle) 
     185    return NULL; 
     186  if(realtime) 
     187    usbdevfs_urb_signal_completion(r5000_process_urb); 
     188  r5kdev = (r5kdev_t *)calloc(1, sizeof(r5kdev_t)); 
     189  r5kdev->handle = handle; 
     190  r5kdev->urbs = NULL; 
     191  r5kdev->cb = cb; 
     192  r5kdev->cb_data = cb_data; 
     193  //r5kdev->realtime = realtime; 
     194#ifdef R5K_DEBUG 
     195   r5kdev->fd = open("r5kdebug.raw", O_WRONLY | O_TRUNC | O_CREAT, 0666); 
     196#endif 
     197  glbl_r5kdev = r5kdev; 
     198  return r5kdev; 
     199} 
     200 
     201int r5000_close(r5kdev_t *r5kdev) 
     202{ 
     203  if(! r5kdev) 
     204    return 0; 
     205  if(r5kdev->urbs) { 
     206    if(r5kdev->streaming) 
     207      r5000_stop_stream(r5kdev); 
     208    r5000_free_urbs(r5kdev); 
     209  } 
     210#ifdef R5K_DEBUG 
     211    if(r5kdev->fd >= 0) 
     212      close(r5kdev->fd); 
     213#endif 
     214  usb_close(r5kdev->handle); 
     215  free(r5kdev); 
     216  return 0; 
     217} 
     218#if 0 
     219void r5000_force_pmt(r5kdev_t *r5kdev, unsigned char *buf) 
     220{ 
     221  int pid = ((buf[1] << 8) | buf[2]) & 0x1fff; 
     222  if(pid == 0x00 && r5000_pmt_state & R5K_PMT_READY) { 
     223    int i; 
     224    for(i = 0; i < r5000_pmt_count; i++) { 
     225      unsigned char *ptr = r5000_pmt + 188*i; 
     226      r5000_pmt_cc = (r5000_pmt_cc +1) &0xf; 
     227      ptr[3] = (ptr[3] & 0xf0) | r5000_pmt_cc; 
     228      r5kdev->cb(ptr, 188, r5kdev->cb_data); 
     229    } 
     230  } else if(pid == 0x21) { 
     231    r5000_pmt_cc = buf[3] & 0xf; 
     232    if(buf[1] & 0x40 && buf[4] == 0x00 && buf[5] == 0x02) { 
     233      if(r5000_pmt_state & R5K_PMT_START) { 
     234        memcpy(r5000_pmt, r5000_pmt_partial, 188 * r5000_pmt_partial_count); 
     235        r5000_pmt_count = r5000_pmt_partial_count; 
     236        r5000_pmt_state |= R5K_PMT_READY; 
     237      } 
     238      memcpy(r5000_pmt_partial, buf, 188); 
     239      r5000_pmt_partial_count = 1; 
     240      r5000_pmt_state |= R5K_PMT_START; 
     241    } else if(r5000_pmt_state & R5K_PMT_START) { 
     242      memcpy(r5000_pmt_partial + 188*r5000_pmt_partial_count, buf, 188); 
     243      r5000_pmt_partial_count++; 
     244    } 
     245  } 
     246} 
     247#else 
     248//taken and adapted from libdtv, (c) Rolf Hakenes 
     249// CRC32 lookup table for polynomial 0x04c11db7 
     250static unsigned int crc_table[256] = { 
     251   0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 
     252   0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 
     253   0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, 
     254   0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, 
     255   0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 
     256   0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 
     257   0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, 
     258   0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, 
     259   0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 
     260   0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 
     261   0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, 
     262   0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, 
     263   0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 
     264   0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 
     265   0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 
     266   0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 
     267   0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 
     268   0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 
     269   0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 
     270   0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 
     271   0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 
     272   0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 
     273   0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, 
     274   0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, 
     275   0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 
     276   0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 
     277   0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, 
     278   0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, 
     279   0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 
     280   0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 
     281   0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, 
     282   0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, 
     283   0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 
     284   0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 
     285   0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 
     286   0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, 
     287   0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 
     288   0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 
     289   0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 
     290   0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 
     291   0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 
     292   0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 
     293   0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4}; 
     294 
     295void r5000_calc_crc(unsigned char *out, const unsigned char *d, int len) 
     296{ 
     297   register int i; 
     298   unsigned int crc = 0xFFFFFFFF; 
     299   const unsigned char *u=(unsigned char*)d; // Saves '& 0xff' 
     300 
     301   for (i=0; i<len; i++) 
     302      crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *u++)]; 
     303 
     304   *out++ = (crc >> 24) & 0xff; 
     305   *out++ = (crc >> 16) & 0xff; 
     306   *out++ = (crc >> 8) & 0xff; 
     307   *out++ = (crc >> 0) & 0xff; 
     308} 
     309 
     310#define IS_VIDEO(x) ((x) == 0x02 || (x) == 0x1b) 
     311void r5000_send_pmt(r5kdev_t *r5kdev) 
     312{ 
     313  if(r5kdev->pmt_pkt[0] != 0x47) { 
     314    int len; 
     315    int i; 
     316    unsigned char *ptr; 
     317    unsigned char ts[188] = { 
     318    0x47, 0x40, 0x21, 0x10, 
     319    0x00, 0x02, 
     320    0xb0, 0x00,  //length 
     321    0x00, 0x01, 
     322    0xc3, 0x00, 0x00, 
     323    0xf0, 0x00,  //PCR_PID 
     324    0xf0, 0x00}; //Program Info Length 
     325    ts[3] = 0x10 | r5kdev->pmt_next_cc; 
     326    printf("Building PMT\n"); 
     327    ptr = ts + 17; 
     328    for(i = 0; i < r5kdev->num_pmt_entries; i++) { 
     329      *ptr++ = r5kdev->pmt[i].id; 
     330      *ptr++ = 0xe0 | (r5kdev->pmt[i].pid>>8); 
     331      *ptr++ = r5kdev->pmt[i].pid & 0xff; 
     332      *ptr++ = 0xf0; 
     333      if(IS_VIDEO(r5kdev->pmt[i].id)) { 
     334        *ptr++ = 0x00; 
     335        ts[13] = 0xe0 | (r5kdev->pmt[i].pid >> 8); 
     336        ts[14] = r5kdev->pmt[i].pid & 0xff; 
     337      } else { 
     338        *ptr++ = 0x06; 
     339        *ptr++ = 0x0a; 
     340        *ptr++ = 0x04; 
     341        *ptr++ = 0x65; 
     342        *ptr++ = 0x6e; 
     343        *ptr++ = 0x67; 
     344        *ptr++ = 0x00; 
     345      } 
     346    } 
     347    ts[7] = (ptr - ts) - 8/*header*/ + 4/*CRC*/; 
     348    r5000_calc_crc(ptr, ts + 5, (ptr - ts) - 5); 
     349    memset(ptr+4, 0xff, 188 - (ptr - ts - 4)); 
     350    memcpy(r5kdev->pmt_pkt, ts, 188); 
     351  } 
     352  r5kdev->pmt_pkt[3] = 0x10 | r5kdev->pmt_next_cc; 
     353  r5kdev->pmt_next_cc = (r5kdev->pmt_next_cc + 1) & 0x0f; 
     354  r5kdev->cb(r5kdev->pmt_pkt, 188, r5kdev->cb_data); 
     355} 
     356 
     357void r5000_add_pmt(r5kdev_t *r5kdev, int pid, int table_id) 
     358{ 
     359  int i; 
     360  int is_video = IS_VIDEO(table_id); 
     361 
     362  for(i = 0; i < r5kdev->num_pmt_entries; i++) { 
     363    if(r5kdev->pmt[i].pid == pid) { 
     364      if(r5kdev->pmt[i].id == table_id) 
     365        return; 
     366      //different table_id for existing pid.  Reset 
     367      r5kdev->num_pmt_entries = 0; 
     368      r5kdev->pmt_state = 0; 
     369      r5kdev->pmt_pkt[0] = 0; 
     370      break; 
     371    } 
     372    if(is_video) { 
     373      if(IS_VIDEO(r5kdev->pmt[i].id)) { 
     374        //a video entry already exists.  Reset 
     375        r5kdev->num_pmt_entries = 0; 
     376        r5kdev->pmt_state = 0; 
     377        r5kdev->pmt_pkt[0] = 0; 
     378        break; 
     379      } 
     380    } 
     381  } 
     382  //Didn't find this PID, add it 
     383  if(i == R5K_MAX_PIDS) 
     384    return; 
     385  printf("Adding %04x: %02x @ %08x\n", pid, table_id, r5kdev->bytes_read); 
     386  r5kdev->pmt[r5kdev->num_pmt_entries].pid = pid; 
     387  r5kdev->pmt[r5kdev->num_pmt_entries].id  = table_id; 
     388  r5kdev->num_pmt_entries++; 
     389  r5kdev->pmt_state |= is_video ? 0x01 : 0x02; 
     390} 
     391 
     392void r5000_force_pmt(r5kdev_t *r5kdev, unsigned char *buf) 
     393{ 
     394  int stream_id, pid, afc, af_size = 0; 
     395  pid = ((buf[1] << 8) | buf[2]) & 0x1fff; 
     396  if(pid == 0x1fff) 
     397    return; 
     398  if(pid == 0) { 
     399    r5kdev->cb(r5000_pat_pkt, 188, r5kdev->cb_data); 
     400    if(r5kdev->pmt_state == 0x03) 
     401      r5000_send_pmt(r5kdev); 
     402  } else { 
     403    if(pid != 0x21) 
     404      r5kdev->cb(buf, 188, r5kdev->cb_data); 
     405    //Only interested in PES packets starting in this TS packet 
     406    if (!buf[1] & 0x40) 
     407      return; 
     408    afc = (buf[3]>>4) & 0x03; 
     409    if(afc == 0x2) 
     410      return; 
     411    if(afc == 0x3) 
     412      af_size = buf[4]+1; 
     413    if(buf[4+af_size] != 0x00 || buf[5+af_size] != 0x00 || buf[6+af_size] != 0x01) 
     414      return; 
     415    //We have a PES packet 
     416    stream_id = buf[7+af_size]; 
     417    if((stream_id & 0xf0) == 0xe0) { 
     418      //Video stream (we need the adaptation field) 
     419      if(afc != 0x03) 
     420        return; 
     421      if(0) { 
     422        int i; 
     423        for(i = 0; i < af_size+8; i++) { 
     424          printf("%02x ", buf[i]); 
     425          if((i %16) == 15) 
     426            printf("\n"); 
     427        } 
     428        printf("\n"); 
     429      } 
     430      if(buf[5] & 0x02) { 
     431        // Has private data, this is MPEG4 
     432        r5000_add_pmt(r5kdev, pid, 0x1b); 
     433      } else if(buf[5] & 0x10) { 
     434        // Has PCR and no private data, this is MPEG2 
     435        r5000_add_pmt(r5kdev, pid, 0x02); 
     436      } 
     437    } else if((stream_id & 0xf0) == 0xc0) { 
     438      //Audio stream 
     439      r5000_add_pmt(r5kdev, pid, 0x04); 
     440    } else if(stream_id  == 0xbd) { 
     441      //Audio stream 
     442      r5000_add_pmt(r5kdev, pid, 0x81); 
     443    } 
     444  } 
     445} 
     446#endif 
     447void r5000_process_block(r5kdev_t *r5kdev, unsigned char *buf, int len) 
     448{ 
     449  int pos; 
     450  int sync = 1; 
     451  if(! r5kdev->streaming) 
     452    return; 
     453  if(len <= 0) 
     454    return; 
     455 
     456  pos = r5kdev->offset; 
     457#ifdef R5K_DEBUG 
     458  if(r5kdev->fd >= 0) 
     459    write(r5kdev->fd, buf, len); 
     460#endif 
     461  while(pos < len) { 
     462      if(buf[pos] != 0x47 || (pos <len-1 && buf[pos+1] == 0xff)) 
     463        goto nosync; 
     464      // If we get here, buf[pos] == 0x47 
     465      if(r5kdev->offset) { 
     466        //previous data exists and is part of a good packet 
     467        memcpy(r5kdev->leftover+188-r5kdev->offset, buf, r5kdev->offset); 
     468        r5000_force_pmt(r5kdev, r5kdev->leftover); 
     469        r5kdev->offset = 0; 
     470      } 
     471      if(pos+188 < len) { 
     472        //at least one full packet is available 
     473        if(buf[pos+188] != 0x47) 
     474          goto nosync; 
     475      } else { 
     476        //Out of data, but the partial packet may be ok. 
     477        memcpy(r5kdev->leftover, buf+pos, len-pos); 
     478        r5kdev->offset = 188-(len-pos); 
     479        break; 
     480      } 
     481      //If we get here, we have a good packet 
     482      r5000_force_pmt(r5kdev, buf+pos); 
     483      if(! sync) 
     484        printf("(%d) Found sync at %08x\n", r5kdev->nexturb, r5kdev->bytes_read+pos); 
     485      sync = 1; 
     486      pos+=188; 
     487      continue; 
     488  nosync: 
     489      r5kdev->offset=0; 
     490      if(sync) 
     491        printf("(%d)Lost sync at %08x\n", r5kdev->nexturb, r5kdev->bytes_read+pos); 
     492      sync = 0; 
     493      pos++; 
     494  } 
     495  r5kdev->bytes_read += len; 
     496} 
     497 
     498int r5000_loop_iterate(r5kdev_t *r5kdev, int timeout_usec) 
     499{ 
     500  struct usb_dev_handle *handle = (struct usb_dev_handle *)r5kdev->handle; 
     501  struct usbdevfs_urb *urbs = (struct usbdevfs_urb *)r5kdev->urbs; 
     502  int len; 
     503  unsigned char *buf; 
     504  struct timeval tv1, tv2; 
     505  if(! r5kdev->streaming) 
     506    return -1; 
     507  gettimeofday(&tv1, NULL); 
     508  len = usb_urb_reap(handle, &urbs[r5kdev->nexturb], timeout_usec); 
     509  gettimeofday(&tv2, NULL); 
     510  //printf("%u.%06u (%u.%06u) Read %d bytes\n", (unsigned int)tv1.tv_sec, (unsigned int)tv1.tv_usec, (unsigned int)tv2.tv_sec, (unsigned int)tv2.tv_usec, len); 
     511  if(len <= 0) { 
     512    if(len != -ETIMEDOUT) 
     513      printf("(%d) Reap failed at %08x: %s\n", r5kdev->nexturb, r5kdev->bytes_read, strerror(errno)); 
     514    return len; 
     515  } 
     516  buf = r5kdev->buffer + (R5K_URB_BUFFER_SIZE*r5kdev->nexturb); 
     517  r5000_process_block(r5kdev, buf, len); 
     518  usb_urb_submit(handle, &urbs[r5kdev->nexturb], NULL); 
     519  r5kdev->nexturb = (r5kdev->nexturb + 1) % MAX_URBS_IN_FLIGHT; 
     520  return 0; 
     521} 
     522 
     523static void r5000_process_urb(struct usbdevfs_urb *urb) 
     524{ 
     525//  struct timeval tv; 
     526//  gettimeofday(&tv, NULL); 
     527//  printf("Callback at %d.%06d: %d/%d\n", tv.tv_sec, tv.tv_usec, urb->buffer_length, urb->actual_length); 
     528  if(urb != &glbl_r5kdev->urbs[glbl_r5kdev->nexturb]) { 
     529    int i; 
     530    for(i = 0; i < MAX_URBS_IN_FLIGHT; i++) { 
     531      if(urb == &glbl_r5kdev->urbs[i]) 
     532      break; 
     533    } 
     534    printf("Discontinuity: Expected %d but got %d!\n", glbl_r5kdev->nexturb, i); 
     535  } 
     536  r5000_process_block(glbl_r5kdev, urb->buffer, urb->actual_length); 
     537  usb_urb_submit(glbl_r5kdev->handle, urb, NULL); 
     538  glbl_r5kdev->nexturb = (glbl_r5kdev->nexturb + 1) % MAX_URBS_IN_FLIGHT; 
     539} 
     540 
     541int r5000_read_status(r5kdev_t *r5kdev, unsigned char *buf) 
     542{ 
     543  return usb_bulk_read(r5kdev->handle, 129, buf, 128, 5000); 
     544} 
     545 
     546int r5000_get_power_state(r5kdev_t *r5kdev) 
     547{ 
     548  unsigned char data1[1]  = { 0x30 }; 
     549  unsigned char data2[0x80]; 
     550  while(1) { 
     551    r5000_read_status(r5kdev, data2); 
     552    usb_bulk_write(r5kdev->handle, 1, data1, 1, 5000); 
     553    usleep(100000); 
     554    if(usb_bulk_read(r5kdev->handle, 1, data2, 2, 5000) == 2 && 
     555       data2[0] == 0x0a || (data2[1] & 0x4e) == 0x4c) 
     556      return !!(data2[1] == 0x4d); 
     557    usleep(100000); 
     558  } 
     559} 
     560 
     561int r5000_toggle_on_off(r5kdev_t *r5kdev) 
     562{ 
     563  unsigned char data1[1]  = { 0x30 }; 
     564  unsigned char data3[0x80], on_off; 
     565  int len; 
     566  on_off = r5000_get_power_state(r5kdev); 
     567  //printf("Start state: %s\n", on_off ? "On" : "Off"); 
     568  usb_bulk_write(r5kdev->handle, 1, data1, 1, 5000); 
     569  usleep(100000); 
     570  usb_bulk_write(r5kdev->handle, 1, (unsigned char *)r5000_button_cmd[R5K_BUTTON_POWER], 0x40, 5000); 
     571  usleep(100000); 
     572  len = usb_bulk_read(r5kdev->handle, 1, data3, 2, 5000); 
     573  usleep(100000); 
     574  while(r5000_get_power_state(r5kdev) == on_off) 
     575    usleep(100000); 
     576  //printf("End state: %s\n", !on_off ? "On" : "Off"); 
     577  return !on_off; 
     578} 
     579 
     580void r5000_change_channel(r5kdev_t *r5kdev, int chan) 
     581{ 
     582  int pos = 1000000, digit; 
     583  unsigned char data2[0x80]; 
     584  r5000_read_status(r5kdev, data2); 
     585  usb_bulk_write(r5kdev->handle, 1, (unsigned char *)r5000_button_cmd[R5K_BUTTON_CLEAR], 0x40, 5000); 
     586  usleep(R5000_BUTTON_DELAY); 
     587  while(pos != 0 && (chan/pos) == 0) 
     588    pos /= 10; 
     589  if(pos == 0) 
     590    pos = 1; 
     591  while(pos != 0) { 
     592    digit = chan / pos; 
     593    usb_bulk_write(r5kdev->handle, 1, (unsigned char *)r5000_button_cmd[digit], 0x40, 5000); 
     594    chan -= digit*pos; 
     595    pos/= 10; 
     596    usleep(R5000_BUTTON_DELAY); 
     597  } 
     598  usb_bulk_write(r5kdev->handle, 1, (unsigned char *)r5000_button_cmd[R5K_BUTTON_ENTER], 0x40, 5000); 
     599} 
  • new file libs/libmythtv/r5000/r5000.h

    - +  
     1#ifndef R5000_H 
     2#define R5000_H 
     3 
     4#define r5kdev_t void 
     5 
     6extern r5kdev_t *r5000_open(unsigned int (*cb)(unsigned char *buffer, int len, void *callback_data), void *cb_data, int realtime); 
     7extern int r5000_close(r5kdev_t *r5kdev); 
     8extern int r5000_start_stream(r5kdev_t *r5kdev); 
     9extern int r5000_stop_stream(r5kdev_t *r5kdev); 
     10extern int r5000_loop_iterate(r5kdev_t *r5kdev, int timeout_usec); 
     11extern int r5000_get_power_state(r5kdev_t *r5kdev); 
     12extern int r5000_toggle_on_off(r5kdev_t *r5kdev); 
     13extern void r5000_change_channel(r5kdev_t *r5kdev, int chan); 
     14#endif //R5000_H 
  • new file libs/libmythtv/r5000/r5000buttons.h

    - +  
     1///This has only been verified for a VIP211.  Quite possibly different buttons are needed for different receivers. 
     2// 
     3#define R5000_BUTTON_DELAY 400000 
     4enum { 
     5  R5K_BUTTON_0 = 0, 
     6  R5K_BUTTON_1, 
     7  R5K_BUTTON_2, 
     8  R5K_BUTTON_3, 
     9  R5K_BUTTON_4, 
     10  R5K_BUTTON_5, 
     11  R5K_BUTTON_6, 
     12  R5K_BUTTON_7, 
     13  R5K_BUTTON_8, 
     14  R5K_BUTTON_9, 
     15  R5K_BUTTON_CLEAR, 
     16  R5K_BUTTON_ENTER, 
     17  R5K_BUTTON_POWER, 
     18  R5K_BUTTON_MAX 
     19}; 
     20const unsigned char r5000_button_cmd[R5K_BUTTON_MAX][0x40] = 
     21{ 
     22//button 0: 
     23{ 
     24 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 
     25 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a, 
     26 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 
     27 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 
     28}, 
     29//button 1: 
     30{ 
     31 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 
     32 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a, 
     33 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 
     34 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 
     35}, 
     36//button 2: 
     37{ 
     38 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 
     39 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a, 
     40 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 
     41 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 
     42}, 
     43//button 3: 
     44{ 
     45 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 
     46 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a, 
     47 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 
     48 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 
     49}, 
     50//button 4: 
     51{ 
     52 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 
     53 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a, 
     54 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 
     55 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 
     56}, 
     57//button 5: 
     58{ 
     59 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 
     60 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a, 
     61 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 
     62 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 
     63}, 
     64//button 6: 
     65{ 
     66 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 
     67 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a, 
     68 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 
     69 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 
     70}, 
     71//button 7: 
     72{ 
     73 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 
     74 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a, 
     75 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 
     76 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 
     77}, 
     78//button 8: 
     79{ 
     80 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 
     81 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a, 
     82 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 
     83 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 
     84}, 
     85//button 9: 
     86{ 
     87 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 
     88 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a, 
     89 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 
     90 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 
     91}, 
     92//Clear: 
     93{ 
     94 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 
     95 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a, 
     96 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 
     97 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 
     98}, 
     99//Enter: 
     100{ 
     101 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x1a, 
     102 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a, 
     103 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 
     104 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 
     105}, 
     106//Power 
     107{ 
     108 0x00, 0x23, 0x0a, 0x80, 0x00, 0x77, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 
     109 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x1a, 
     110 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x3a, 0x04, 0x1a, 0x04, 0x1a, 0x04, 0x1a, 
     111 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x1a, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x0e, 
     112} 
     113};