#include "PrgConfigWidget.h"
#include <stdio.h>
#include <qhbox.h>
#include <qvbox.h>
#include <qstringlist.h>
#include <qcombobox.h>
#include <qlabel.h>
#include <qlineedit.h>
#include <qpushbutton.h>
#include <qlayout.h>
#include <qgroupbox.h>
#include <qtooltip.h>
#include <qwidgetstack.h>
#include <qradiobutton.h>
#include <qbuttongroup.h>
#include <qslider.h>
#include <qspinbox.h>
#include <qgrid.h>

#include <klocale.h>
#include <kiconloader.h>
#include <kmessagebox.h>

#include "hardware.hh"
#include "uparport.hh"
#include "serport.hh"
#include "bootstrap555.hh"

#include "Config.h"
#include <iostream>
#include <cstdio>
#include "assert.h"

using namespace std ;

QStringList PrgConfigWidget::parports_;
QStringList PrgConfigWidget::serports_;


PrgConfigWidget::PrgConfigWidget ( hardware *hrd):
        ConfigWidget(0), phard(hrd),
        null_prog_name(i18n("<Select here a predefined configuration>"))
{
    QString type , device;
    int vp, vd, cl, out, in, rw, clkdelay ;
    port *current_port = 0;


    KIconLoader loader;
    QIconSet iconset = loader.loadIcon("filesave", KIcon::Toolbar) ;

    // QStringList devlist = getParportList() ;
    static QString invPin(i18n("Check this option if your hardware uses negative logic for this pin")) ;
    static QString testpin(i18n("Check this box to turn voltage on/off for this pin")) ;

    // load the current config
    Config::getCurrentPortConfig(type,device,vp,vd,cl,out,in,rw,clkdelay ) ;


    central = new QVBox(this) ;
    central->setSpacing(8) ;
    central->setFrameStyle( QFrame::Panel | QFrame::Sunken );
    central->setLineWidth( 2 );
    central->setMargin(8) ;


    // 0) Standard programmers
    QGroupBox *stdbox = new QGroupBox (1,Horizontal,i18n("Standard cards"),central) ;
    QHBox *stdhbox = new QHBox(stdbox) ;
    stdhbox->setSpacing(5) ;
    stdh = new QComboBox(stdhbox) ;
    QToolTip::add
        (stdh, i18n("Select here a standard configuration.\n"
                    "You can edit the configuration name and save your own configuration.\n"
                    "Build-in standard configurations cannot be overwritten." )) ;
    stdh->insertItem(null_prog_name) ;
    stdh->insertStringList(  Config::getStdHardwares() ) ;
    stdh->setEditable(true) ;
    stdsav = new QPushButton(i18n("Save"), stdhbox) ;
    stdsav->setPixmap(iconset.pixmap()) ;
    QToolTip::add
        (stdsav, i18n("Add the current configuration to the standard configurations list") ) ;

    stdhbox->setStretchFactor(stdh,10) ;
    stdhbox->setStretchFactor(stdsav,1) ;

    stdbox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed) ;


    QString port_toolt_tip(i18n("Select here the port type you need.\n"
                                " (Don't forget to click <Apply> or <Ok> to validate your selection)")) ;
    // 1) Port choice
    //
    QGroupBox *devbox = new QGroupBox (5,Horizontal,i18n("Port and driver selection"),central) ;

    QGrid * grid = new QGrid(  3  ,Qt::Horizontal, devbox ) ;
    grid->setSpacing(6) ;



    butpar = new QRadioButton(grid) ;
    QToolTip::add
        ( butpar,port_toolt_tip) ;
    butpar->setText(i18n("Parallel")) ;

    butser = new QRadioButton(grid) ;
    butser->setText(i18n("Serial")) ;
    QToolTip::add
        ( butser,port_toolt_tip) ;

    butser555 = new QRadioButton(grid) ;
    butser555->setText(i18n("Serial-555")) ;
    QToolTip::add
        ( butser555,port_toolt_tip) ;
    // temporary disabled
    butser555->setEnabled(false) ;

    radiobuttons = new QButtonGroup(this) ;
    radiobuttons->insert( butpar , 0) ;
    radiobuttons->insert( butser , 1 ) ;
    radiobuttons->insert( butser555, 2  ) ;

    parportlist = new QComboBox(grid) ;
    parportlist->insertStringList(parports_);
    QToolTip::add
        (parportlist,i18n("Available ports list:\n"
                          "If this list is empty, your machine might not have any parallel port\n"
                          "or the /dev/parportX device has not been created.\n"
                          "use \"mknod /dev/parport0 c 99 0\" to create it.\n"
                          "use \"chmod a+rw /dev/parport0\" to make it RW enabled.")) ;

    //   (new QHBox(devbox))->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed) ;
    parportlist->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed) ;

    serportlist = new QComboBox(grid) ;
    serportlist->insertStringList(serports_);
    QToolTip::add
        (serportlist,i18n("Available ports list:\n"
                          "If this list is empty, your machine might not have any serial port")) ;
    serportlist->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed) ;

    ser555portlist = new QComboBox(grid) ;
    ser555portlist->insertStringList(serports_);
    QToolTip::add
        (ser555portlist,i18n("Available ports list:\n"
                             "If this list is empty, your machine might not have any serial port")) ;
    ser555portlist->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed) ;

    // temporary disabled
    ser555portlist->setEnabled(false) ;

    devbox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed) ;


    // 2) GroupBox for pins assignment
    QGroupBox *group = new QGroupBox(4,Horizontal,i18n("Pin assignment"),central) ;
    group->addSpace(0) ;
    (void)new QLabel(i18n("Pin #"), group) ;
    (void)new QLabel(i18n("Inverted"), group) ;
    QToolTip::add
        (new QLabel(i18n("Pin test"), group) ,
                i18n("Click Apply to validate you configuration,"
                     " then try it with the above checkboxes")) ;

    // 2-1) Vpp pin
    (void)new QLabel("Vpp", group) ;
    vpp = new QComboBox(group) ;
    QToolTip::add
        (vpp,i18n("The VPP pin is used to select the high voltage programming mode.")) ;
    ivpp = new QCheckBox(group) ;
    QToolTip::add
        (ivpp,invPin) ;
    cbvpp = new QCheckBox("0 V", group) ;
    QToolTip::add
        (cbvpp,testpin) ;
    connect(cbvpp, SIGNAL(clicked()), this,   SLOT(slotvpp())) ;


    // 2-2) Vdd pin
    (void)new QLabel("Vdd", group) ;
    vdd = new QComboBox(group) ;
    QToolTip::add
        (vdd,i18n("The VDD pin is used to apply 5V to the programmed device.\nMust be set to NA if your programmer doesn't control the VDD line.")) ;
    ivdd = new QCheckBox(group) ;
    QToolTip::add
        (ivdd,invPin) ;
    cbvdd = new QCheckBox("0 V", group) ;
    QToolTip::add
        (cbvdd,testpin) ;
    connect(cbvdd, SIGNAL(clicked()), this,   SLOT(slotvdd())) ;

    // 2-3) Clock pin
    (void)new QLabel("Clock", group) ;
    clock = new QComboBox(group) ;
    QToolTip::add
        (clock,i18n("The CLOCK pin is used to synchronize serial"
                    " data of the DATA IN and DATA OUT pins.") );
    iclock = new QCheckBox(group) ;
    QToolTip::add
        (iclock,invPin) ;
    cbclock = new QCheckBox("0 V", group) ;
    QToolTip::add
        (cbclock,testpin) ;
    connect(cbclock, SIGNAL(clicked()), this,   SLOT(slotclock())) ;

    // 2-4) Data in pin
    (void)new QLabel("Data in", group) ;
    din = new QComboBox(group) ;
    QToolTip::add
        (din,i18n("The DATA IN pin is used to receive data from the programmed device" ) ) ;
    idin = new QCheckBox(group) ;
    QToolTip::add
        (idin,invPin) ;
    cbdatain = new QCheckBox("0 V", group) ;
    QToolTip::add
        (cbdatain,i18n("This pin is driven by the programmed device\n"
                       "Without device, it must follow the \"Data out\" pin (if power on) ") ) ;
    cbdatain->setEnabled(false) ;


    // 2-5) Data out pin
    (void)new QLabel("Data out", group) ;
    dout = new QComboBox(group) ;
    QToolTip::add
        (dout,i18n("The DATA OUT pin is used to send data to the programmed device" ) ) ;
    idout = new QCheckBox(group) ;
    idout->setChecked(out < 0) ;
    QToolTip::add
        (idout,invPin) ;
    cbdataout = new QCheckBox("0 V", group) ;
    connect(cbdataout, SIGNAL(clicked()), this,   SLOT(slotdataout())) ;
    QToolTip::add
        (cbdataout,testpin) ;


    // 2-6) Data RW pin
    (void)new QLabel("Data R/W", group);
    drw = new QComboBox(group);
    QToolTip::add
        (drw,i18n("The DATA RW pin selects the direction of data buffer.\nMust be set to NA if your programmer does not use bi-directionnal buffer."));
    connect(drw, SIGNAL(activated(const QString&)), this, SLOT(slotrwchange(const QString&)));
    idrw = new QCheckBox(group);
    idrw->setChecked(rw<0);
    QToolTip::add
        (idrw,invPin);
    cbrw = new QCheckBox("Data In", group);
    connect(cbrw, SIGNAL(clicked()), this, SLOT(slotrw()));
    QToolTip::add
        (cbrw,i18n("Check this box to change DATA buffer direction"));



    // 3) "Verify config" button
    new QHBox(group) ;
    new QHBox(group) ;
    new QHBox(group) ;

    bsendbits = new QPushButton(i18n("Send 0xA55A"),group) ;
    connect(bsendbits,  SIGNAL(clicked()), this, SLOT(sendBits())) ;
    QToolTip::add
        (bsendbits, i18n("Continuously send 0xA55A on \"Data out\" pin")) ;

    group->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed) ;


    QGroupBox *delaybox = new QGroupBox (2,Horizontal,i18n("Clock delay"),central) ;
    QToolTip::add
        (delaybox, i18n("Some programming cards need low clock rate:\n"
                        "adding delay to clock pulses might help.")) ;
    delay_slider = new QSlider(0,50,5,0,Horizontal,delaybox) ;
    QSpinBox *delay_spinbox = new QSpinBox(0,50,1,delaybox) ;
    connect(delay_slider,SIGNAL(valueChanged(int)), delay_spinbox, SLOT(setValue(int))) ;
    connect(delay_spinbox,SIGNAL(valueChanged(int)), delay_slider, SLOT(setValue(int))) ;
    delay_slider->setValue(clkdelay) ;

    //    new QVBox(central) ;
    setMinimumWidth(sizeHint().width() +50) ;


    if( phard && phard->isok())
    {
        // set all the pins low
        phard->clklo() ;
        phard->outlo();
        phard->vppoff() ;
        phard->vddoff() ;
        phard->rwread();
    }


    // create Timer for sending bits
    timersendbits = new QTimer(this) ;
    connect(  timersendbits  , SIGNAL(timeout()), this, SLOT(slotSendBits())) ;

    // create timer for automatically poll dataout pin
    timerpolldataout =  new QTimer(this) ;
    connect(  timerpolldataout  , SIGNAL(timeout()), this, SLOT(slotupdatedatain())) ;
    timerpolldataout->start(100, false) ;

    connect(radiobuttons, SIGNAL( clicked(int)), this, SLOT(driverSelected(int)) ) ;

    if(type == "parallel")
        butpar->setChecked(true), current_port = new parport  ;
    else if(type == "serial")
        butser->setChecked(true) , current_port = new serport ;
    else if(type == "boot555")
        butser555->setChecked(true) , current_port = new bootstrap555;

    connect(stdh, SIGNAL(activated(const QString&)), this, SLOT(slotStdHardware(const QString&)) ) ;
    connect(stdsav, SIGNAL(clicked()), this, SLOT(slotSaveHardware()) ) ;

    // the port is just used by reconfigCombos a pin number provider
    if( current_port)
        reconfigCombos(current_port, vp,vd,cl,out,in,rw,clkdelay) ;
    delete current_port ;

    show() ;
}



//
// ask OS for valid an available parports  (static method)
// must be called before any port allocation because an
// allocated parport is not seen as available
// I do not use anymore the "ls /dev/parportX" method
// because it reports ALL the existing /dev/parport inodes
// (and not only the physically existing ones)
//
void PrgConfigWidget::availablePorts()
{
    char name[100] ;
#if 1
    //
    // standard parport in user space
    //
    for(int i = 0 ; i < 8 ; ++i)
    {
        sprintf(name,"/dev/parport%d", i) ;
        if( parport::probePort(name)== 0)    // available ?
            parports_ += name ;
    }
    //
    // new devfs parport flavour
    //
    for(int i = 0 ; i < 8 ; ++i)
    {
        sprintf(name,"/dev/parports/%d", i) ;
        if( parport::probePort(name) == 0 )   // available ?
            parports_ += name ;
    }
#else
    parports_ += "/dev/parport0" ;
#endif

    //
    // standard serport in user space
    //
    for(int i = 0 ; i < 8 ; ++i)
    {
        sprintf(name,"/dev/ttyS%d", i) ;
        if( serport::probePort(name)== 0)    // available ?
            serports_ += name ;
    }
    //
    // new devfs serport flavour
    //
    for(int i = 0 ; i < 8 ; ++i)
    {
        sprintf(name,"/dev/tts/%d", i) ;
        if( serport::probePort(name) == 0 )   // available ?
            serports_ += name ;
    }

    //
    // standard USB serport in user space
    //
    for(int i = 0 ; i < 8 ; ++i)
    {
        sprintf(name,"/dev/ttyUSB%d", i) ;
        if( serport::probePort(name)== 0)    // available ?
            serports_ += name ;
    }
    //
    // new devfs USB serport flavour
    //
    for(int i = 0 ; i < 8 ; ++i)
    {
        sprintf(name,"/dev/usb/tts/%d", i) ;
        if( serport::probePort(name) == 0 )   // available ?
            serports_ += name ;
    }

}




void  PrgConfigWidget::doApply()
{
    int vp = pinNumber(vpp->currentText()) ;
    if( ivpp->isChecked() )
        vp = -vp ;

    int vd = pinNumber(vdd->currentText()) ;
    if( ivdd->isChecked() )
        vd = -vd ;

    int clo = pinNumber(clock->currentText()) ;
    if( iclock->isChecked() )
        clo = -clo ;

    int di = pinNumber(din->currentText()) ;
    if( idin->isChecked() )
        di = -di ;

    int dou = pinNumber(dout->currentText()) ;
    if( idout->isChecked() )
        dou = -dou ;

    int rw = pinNumber(drw->currentText()) ;
    if( idrw->isChecked() )
        rw = -rw ;

    QString type , port ;
    if(butpar->isOn())
    {
        type = "parallel"  ;
        port =  parportlist->currentText() ;
    }
    else if(butser->isOn())
    {
        type = "serial"  ;
        port =  serportlist->currentText() ;
    }

    int clkdelay  = delay_slider->value() ;
    // blank port == port unavailable
    if( port != "")
    {
        Config::setPortConfig(type,port,vp,vd,clo,dou,di,rw, clkdelay );
        phard->setpins(type.latin1(),port.latin1(),vp,vd,clo,dou,di,rw,clkdelay );
    }
    else
    {
        KMessageBox::detailedSorry(this,
                                    i18n("Port not available"),
                                    i18n("The selected port is not present on your system, or is not RW enabled.\n"
                                         "Port selection refused.") ) ;
    }

    //Reset status of pins graphically because inside phard->setpins() reset electrically...
    cbvpp->setText("0 V");
    cbvpp->setChecked(false);
    cbvdd->setText("0 V");
    cbvdd->setChecked(false);
    cbclock->setText("0 V");
    cbclock->setChecked(false);
    cbdataout->setText("0 V");
    cbdataout->setChecked(false);
    cbrw->setText("Data In");
    cbrw->setChecked(false);

    emit PrgConfigChanged();
}



void PrgConfigWidget::sendBits()
{
    if( timersendbits->isActive())
    {
        bsendbits->setText(i18n("Send 0xA55A")) ;
        timersendbits->stop() ;
        slotdataout() ;
    }
    else
    {
        bsendbits->setText(i18n("Stop")) ;
        timersendbits->start(1,false) ;
    }
}



void PrgConfigWidget::slotrwchange(const QString & string)
{
    if(!phard->isok())
        return ;

    bool  enable =  pinName(string) != "(NA)"    ;
    cbrw->setEnabled(enable);
    idrw->setEnabled(enable);
}



void PrgConfigWidget::slotvpp()
{
    if(!phard->isok())
        return ;

    if( cbvpp->isOn())
    {
        cbvpp->setText("13 V") ;
        phard->vppon() ;
    }
    else
    {
        cbvpp->setText("0 V") ;
        phard->vppoff() ;
    }
    slotupdatedatain()  ;
}


void PrgConfigWidget::slotvdd()
{
    if(!phard->isok())
        return ;

    if( cbvdd->isOn())
    {
        cbvdd->setText("5 V") ;
        phard->vddon() ;
    }
    else
    {
        cbvdd->setText("0 V") ;
        phard->vddoff() ;
    }
}


void PrgConfigWidget::slotclock()
{
    if(!phard->isok())
        return ;

    if( cbclock->isOn())
    {
        cbclock->setText("5 V") ;
        phard->clkhi() ;
    }
    else
    {
        cbclock->setText("0 V") ;
        phard->clklo() ;
    }
}


void PrgConfigWidget::slotdataout()
{
    if(!phard->isok())
        return ;

    if( cbdataout->isOn())
    {
        cbdataout->setText("5 V") ;
        phard->outhi() ;
    }
    else
    {
        cbdataout->setText("0 V") ;
        phard->outlo() ;
    }
}


void PrgConfigWidget::slotrw()
{
    if(!phard->isok())
        return ;

    if( cbrw->isOn())
    {
        cbrw->setText("Data Out") ;
        phard->rwwrite() ;
    }
    else
    {
        cbrw->setText("Data In") ;
        phard->rwread() ;
    }
}


void PrgConfigWidget::slotupdatedatain()
{

    if(!phard->isok())
        return ; // port not open/owned

    static int oldstate = 0 ;
    int state =  phard->inbit() ;

    if( state == oldstate )
        return ;

    if( state  )
    {
        cbdatain->setChecked(true) ;
        cbdatain->setText("5 V") ;
    }
    else
    {
        cbdatain->setChecked(false) ;
        cbdatain->setText("0 V") ;
    }
    oldstate = state ;
}


void PrgConfigWidget::send_bits( unsigned int d , int nbb)
{
    if( phard && phard->isok())
    {
        phard->rwwrite() ;
        for(  ;  nbb ; --nbb  )
        {
            phard->clkhi();				/* Clock high */

            if ( d & 0x01 )
                phard->outhi();				/* Output a 1 */
            else
                phard->outlo();				/* Output a 0 */

            phard->clklo();				/* Clock lo */

            d >>= 1;							/* Move the data over 1 bit */
        }

        phard->outlo();				/* let data line in 0 state */
        phard->rwread() ;
    }
}


/** No descriptions */
void PrgConfigWidget::slotSendBits()
{
    send_bits(0xA55A,16) ;
}


/** Search the pin number "pin" in the string list "list".
\return The index of the found pin , or -1 if not found
 */
int PrgConfigWidget::findPin(const QStringList &list, int pin)
{
    QStringList::const_iterator i ;
    int k ;
    for(i=list.begin(), k = 0  ; i != list.end() ; ++i, ++k )
    {
        if( pinNumber(*i) == pin)
            return k ;
    }
    return -1 ;
}


/** Convert a pin name to pin number
(a pin name must be a numeric decimal string  eventually followed by a blank and an arbitrary text)
\return A pin number, or -1 if the pinname is malformed
*/
int PrgConfigWidget::pinNumber(const QString& pinname)
{
    int pp = -1;
    sscanf(pinname.latin1(),"%d",&pp ) ;
    return pp ;
}



void PrgConfigWidget::reconfigCombos(port *aport, int vp, int vd, int cl,
                                     int out, int in, int rw, int clkdelay )
{
    int k, pin;

    //Lists of pin...
    QStringList outplist = QStringList::split(',', aport->outputPinsList());
    QStringList inplist = QStringList::split(',', aport->inputPinsList());

    // 2-1) Vpp pin
    vpp->clear() ;
    vpp->insertStringList(outplist);
    pin = vp ;
    if(pin < 0 )
        pin = -pin ;
    if((k=findPin(outplist,pin)) == -1)
        k = 0 ;
    vpp->setCurrentItem(k) ;
    ivpp->setChecked(vp < 0) ;


    // 2-2) Vdd pin
    vdd->clear() ;
    vdd->insertStringList(outplist);
    pin = vd ;
    if(pin < 0 )
        pin = -pin ;
    if((k=findPin(outplist,pin)) == -1)
        k = 0 ;
    vdd->setCurrentItem(k) ;
    ivdd->setChecked(vd < 0) ;


    // 2-3) Clock pin
    clock->clear() ;
    clock->insertStringList(outplist);
    pin = cl ;
    if(pin < 0 )
        pin = -pin ;
    if((k=findPin(outplist,pin)) == -1)
        k = 0 ;
    clock->setCurrentItem(k) ;
    iclock->setChecked(cl < 0) ;

    // 2-4) Data in pin
    din->clear() ;
    din->insertStringList(inplist);
    pin = in ;
    if(pin < 0 )
        pin = -pin ;
    if((k=findPin(inplist,pin)) == -1)
        k = 0 ;
    din->setCurrentItem(k) ;
    idin->setChecked(in < 0) ;

    // 2-5) Data out pin
    dout->clear() ;
    dout->insertStringList(outplist);
    pin = out ;
    if(pin < 0 )
        pin = - pin ;
    if((k=findPin(outplist,pin)) == -1)
        k = 0 ;
    dout->setCurrentItem(k) ;
    idout->setChecked(out < 0) ;

    // 2-5) Data out pin
    drw->clear();
    drw->insertStringList(outplist);
    pin=rw;
    if (pin<0 )
        pin = -pin ;
    if ((k=findPin(outplist,pin))==-1)
        k=0;
    drw->setCurrentItem(k);
    idrw->setChecked(rw < 0);
    slotrwchange(drw->currentText()) ;

    // 2-6) clock delay
    delay_slider->setValue(clkdelay) ;
}



/** Changes pin/port configuration when a new standard hardware is selected */
void PrgConfigWidget::slotStdHardware(const QString& name)
{

    if( name == null_prog_name )
        return  ;
    // restore the initial item (which is a message)
    stdh->setCurrentItem(0) ;

    QString type ;
    int vpp,vdd,clock,dataout,datain,drw, clkdelay;
    port *aport ;

    //++Mirko!!
    Config::getHardConfig(name, type, vpp,  vdd,  clock,  dataout, datain, drw, clkdelay);
    //--Mirko!!

    if( type == "parallel" )
    {
        aport = new parport ;
        butpar->setChecked(true) ;
    }
    else if( type == "serial" )
    {
        aport = new serport ;
        butser->setChecked(true) ;
    }
    else if( type == "boot555" )
    {
        aport = new bootstrap555 ;
        butser555->setChecked(true) ;
    }
    else
        return ;

    reconfigCombos(aport ,vpp,  vdd,  clock,  dataout, datain, drw, clkdelay ) ;

    delete aport ;
}


/** No descriptions */
void PrgConfigWidget::slotSaveHardware()
{
    QString name = stdh->currentText() ;
    if(name == null_prog_name)
        return ;


    int vp = pinNumber(vpp->currentText()) ;
    if( ivpp->isChecked() )
        vp = -vp ;

    int vd = pinNumber(vdd->currentText()) ;
    if( ivdd->isChecked() )
        vd = -vd ;

    int clo = pinNumber(clock->currentText()) ;
    if( iclock->isChecked() )
        clo = -clo ;

    int di = pinNumber(din->currentText()) ;
    if( idin->isChecked() )
        di = -di ;

    int dou = pinNumber(dout->currentText()) ;
    if( idout->isChecked() )
        dou = -dou ;

    int datarw = pinNumber(drw->currentText()) ;
    if( idrw->isChecked() )
        datarw = -datarw ;

    QString type ;
    if( butpar->isOn() )
        type =  "parallel" ;
    else if( butser->isOn() )
        type =  "serial" ;
    else
        type = "boot555" ;

    int clkdelay = delay_slider->value() ;
    Config::setHardConfig(name, type, vp, vd, clo, dou, di, datarw, clkdelay);

    // update combo box
    stdh->clear() ;
    stdh->insertItem(null_prog_name) ;
    stdh->insertStringList(  Config::getStdHardwares() ) ;
    stdh->setCurrentItem( 0  ) ;
}
/** No descriptions */
const QString PrgConfigWidget::pinName(const QString &pinname)
{
    char name[20] ;
    int k = sscanf(pinname.latin1(),"%*d %19s", name) ;
    return ( k ==1)  ? name : "" ;
}

QString PrgConfigWidget::configName()
{
    return i18n("Builtin Programmer") ;
}
QString PrgConfigWidget::configTitle()
{
    return i18n("Builtin Programmer configuration") ;
}

QPixmap PrgConfigWidget::icon()
{
    KIconLoader loader;
    return loader.loadIcon("pikdev_config_prg", KIcon::Toolbar, KIcon::SizeMedium) ;
}


/** No descriptions */
void PrgConfigWidget::driverSelected(int drv)
{
    QString xport;
    int vp,vd,cl,out,in,k,rw,clkdelay ;
    port *port = 0 ;
    parport pport;
    serport sport ;
    bootstrap555 s555port ;

    if( drv == 0)
    {
        Config::getParPortConfig(xport,vp,vd,cl,out,in,rw,clkdelay) ;
        if((k=parports_.findIndex(xport)) == -1)
            k = 0 ;
        parportlist->setCurrentItem(k) ;
        port = &pport ;
    }
    else if( drv == 1)
    {
        Config::getSerPortConfig(xport,vp,vd,cl,out,in,rw,clkdelay ) ;
        if((k=serports_.findIndex(xport)) == -1)
            k = 0 ;
        serportlist->setCurrentItem(k) ;
        port = &sport ;
    }
    else if( drv == 2)
    {
        Config::getSer555PortConfig(xport,vp,vd,cl,out,in,rw,clkdelay ) ;
        if((k=serports_.findIndex(xport)) == -1)
            k = 0 ;
        ser555portlist->setCurrentItem(k) ;
        port = &s555port ;
    }
    if(port)
        reconfigCombos(port, vp,  vd,  cl, out, in, rw, clkdelay ) ;
}
