/***************************************************************************
* Copyright ( C ) 2005 - 2007 Nicolas Hadacek < hadacek @ kde . org > *
* *
* This program is free software ; you can redistribute it and / or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation ; either version 2 of the License , or *
* ( at your option ) any later version . *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "device_xml_to_data.h"
# include <tqdir.h>
# include <tqfile.h>
# include <tqtextstream.h>
# include <tqregexp.h>
bool Device : : XmlToDataBase : : getFrequencyRange ( OperatingCondition oc , Special special , TQDomElement element )
{
TQDomElement range ;
for ( TQDomNode child = element . firstChild ( ) ; ! child . isNull ( ) ; child = child . nextSibling ( ) ) {
if ( child . nodeName ( ) ! = " frequency_range " ) continue ;
if ( ! child . isElement ( ) ) tqFatal ( " \" frequency_range \" should be an element " ) ;
if ( child . toElement ( ) . attribute ( " name " ) ! = oc . key ( ) ) continue ;
Special s = Special : : fromKey ( child . toElement ( ) . attribute ( " special " ) ) ;
if ( s = = Special : : Nb_Types ) tqFatal ( " Unrecognized special " ) ;
if ( special ! = s ) continue ;
if ( ! range . isNull ( ) ) tqFatal ( " Duplicated \" frequency_range \" " ) ;
range = child . toElement ( ) ;
}
if ( range . isNull ( ) ) return false ;
FrequencyRange frange ;
frange . operatingCondition = oc ;
frange . special = special ;
for ( TQDomNode child = range . firstChild ( ) ; ! child . isNull ( ) ; child = child . nextSibling ( ) ) {
if ( child . nodeName ( ) = = " frequency " ) {
if ( ! child . isElement ( ) ) tqFatal ( " Frequency is not an element " ) ;
TQDomElement frequency = child . toElement ( ) ;
bool ok1 , ok2 , ok3 , ok4 ;
RangeBox box ;
box . start . x = frequency . attribute ( " start " ) . toDouble ( & ok1 ) ;
box . end . x = frequency . attribute ( " end " ) . toDouble ( & ok2 ) ;
box . start . yMin = frequency . attribute ( " vdd_min " ) . toDouble ( & ok3 ) ;
box . start . yMax = frequency . attribute ( " vdd_max " ) . toDouble ( & ok4 ) ;
box . end . yMax = box . start . yMax ;
if ( ! ok1 | | ! ok2 | | ! ok3 | | ! ok4
| | box . start . x < 0.0 | | box . start . x > box . end . x
| | box . start . yMin < 0.0 | | box . start . yMin > box . start . yMax )
tqFatal ( " Malformed frequency element " ) ;
if ( frequency . attribute ( " vdd_min_end " ) . isEmpty ( ) ) box . end . yMin = box . start . yMin ;
else {
box . end . yMin = frequency . attribute ( " vdd_min_end " ) . toDouble ( & ok1 ) ;
if ( ! ok1 | | box . end . yMin > box . end . yMax ) tqFatal ( " Malformed frequency element " ) ;
}
box . mode = frequency . attribute ( " mode " ) ;
box . osc = frequency . attribute ( " osc " ) ;
box . special = frequency . attribute ( " special " ) ;
for ( uint i = 0 ; i < uint ( frange . vdds . count ( ) ) ; i + + )
if ( box . start . x < frange . vdds [ i ] . end . x & & box . end . x > frange . vdds [ i ] . start . x ) {
if ( box . mode . isEmpty ( ) & & box . osc . isEmpty ( ) & & box . special . isEmpty ( ) )
tqFatal ( " Overlapping frequency ranges " ) ;
continue ; // #### FIXME: ignore additionnal mode
}
// tqDebug("add Freq Range: %s %s %f=[%f %f] %f=[%f %f]",
// Device::FrequencyRange::TYPE_LABELS[type], Device::FrequencyRange::SPECIAL_LABELS[type],
// box.start.x, box.start.yMin, box.start.yMax,
// box.end.x, box.end.yMin, box.end.yMax);
frange . vdds . append ( box ) ;
}
}
if ( frange . vdds . count ( ) = = 0 ) tqFatal ( " Empty frequency range " ) ;
_data - > _frequencyRanges . append ( frange ) ;
return true ;
}
bool Device : : XmlToDataBase : : getMemoryTechnology ( TQDomElement element )
{
TQString s = element . attribute ( " memory_technology " ) ;
_data - > _memoryTechnology = MemoryTechnology : : fromKey ( s ) ;
if ( _data - > _memoryTechnology ! = MemoryTechnology : : Nb_Types ) return true ;
if ( ! s . isNull ( ) ) tqFatal ( " Unrecognized memory technology " ) ;
return false ;
}
void Device : : XmlToDataBase : : processDevice ( TQDomElement device )
{
TQString name = device . attribute ( " name " ) . upper ( ) ;
if ( name . isEmpty ( ) ) tqFatal ( " Device has no name " ) ;
if ( _map . contains ( name ) ) tqFatal ( TQString ( " Device \" %1 \" already defined " ) . arg ( name ) ) ;
_data = createData ( ) ;
_map [ name ] = _data ;
_data - > _name = name ;
_data - > _alternatives = TQStringList : : split ( ' ' , device . attribute ( " alternative " ) ) ;
if ( _data - > _alternatives . count ( ) ) _alternatives [ name ] = _data - > _alternatives ;
_data - > _status = Status : : fromKey ( device . attribute ( " status " ) ) ;
switch ( _data - > _status . type ( ) ) {
case Status : : Nb_Types :
tqFatal ( " Unrecognized or absent device status " ) ;
break ;
case Status : : Future :
if ( _data - > _alternatives . count ( ) ) tqFatal ( " Future device has alternative " ) ;
break ;
case Status : : NotRecommended :
case Status : : Mature :
if ( _data - > _alternatives . count ( ) = = 0 ) warning ( " Not-recommended/mature device has no alternative " ) ;
break ;
case Status : : InProduction :
case Status : : EOL :
case Status : : Unknown : break ;
}
// document
_data - > _documents . webpage = device . attribute ( " document " ) ; // ### REMOVE ME
TQDomElement documents = findUniqueElement ( device , " documents " , TQString ( ) , TQString ( ) ) ;
if ( documents . isNull ( ) ) {
if ( _data - > _documents . webpage . isEmpty ( ) ) tqFatal ( " Missing \" documents \" element " ) ;
} else {
if ( ! _data - > _documents . webpage . isEmpty ( ) ) tqFatal ( " document should be removed from root element " ) ;
_data - > _documents . webpage = documents . attribute ( " webpage " ) ;
if ( _data - > _documents . webpage . isEmpty ( ) ) tqFatal ( " Missing webpage " ) ;
_data - > _documents . datasheet = documents . attribute ( " datasheet " ) ;
TQRegExp rexp ( " \\ d{5} " ) ;
if ( _data - > _documents . datasheet = = " ? " ) warning ( " No datasheet specified " ) ;
if ( ! rexp . exactMatch ( _data - > _documents . datasheet ) ) tqFatal ( TQString ( " Malformed datasheet \" %1 \" (5 digits) " ) . arg ( _data - > _documents . datasheet ) ) ;
_data - > _documents . progsheet = documents . attribute ( " progsheet " ) ;
if ( _data - > _documents . progsheet = = " ? " ) warning ( " No progsheet specified " ) ;
if ( ! rexp . exactMatch ( _data - > _documents . datasheet ) ) tqFatal ( TQString ( " Malformed progsheet \" %1 \" (5 digits) " ) . arg ( _data - > _documents . progsheet ) ) ;
_data - > _documents . erratas = TQStringList : : split ( " " , documents . attribute ( " erratas " ) ) ;
for ( uint i = 0 ; i < uint ( _data - > _documents . erratas . count ( ) ) ; i + + ) {
TQString errata = _data - > _documents . erratas [ i ] ;
if ( ! rexp . exactMatch ( errata ) ) {
TQRegExp rexp2 ( " \\ d{5}e \\ d " ) ;
if ( ! rexp2 . exactMatch ( errata ) & & ! errata . startsWith ( " er " ) & & errata . mid ( 2 ) ! = _data - > _name . lower ( ) )
tqFatal ( TQString ( " Malformed erratas \" %1 \" (5 digits or 5 digits + e + 1 digit or \" er \" + name) " ) . arg ( errata ) ) ;
}
}
}
if ( _data - > _documents . webpage = = " ? " ) warning ( " No webpage specified " ) ;
else {
TQRegExp rexp ( " \\ d{6} " ) ;
if ( ! rexp . exactMatch ( _data - > _documents . webpage ) ) tqFatal ( TQString ( " Malformed webpage \" %1 \" (6 digits) " ) . arg ( _data - > _documents . webpage ) ) ;
if ( _documents . contains ( _data - > _documents . webpage ) )
tqFatal ( TQString ( " webpage duplicated (already used for %1) " ) . arg ( _documents [ _data - > _documents . webpage ] ) ) ;
_documents [ _data - > _documents . webpage ] = name ;
}
// frequency ranges
TQStringList names ;
bool ok = false ;
FOR_EACH ( OperatingCondition , oc ) {
names + = oc . key ( ) ;
FOR_EACH ( Special , special )
if ( getFrequencyRange ( oc , special , device ) & & special = = Special : : Normal ) ok = true ;
}
if ( ! ok ) tqWarning ( " No normal frequency range defined " ) ;
checkTagNames ( device , " frequency_range " , names ) ;
// memory technology
if ( ! getMemoryTechnology ( device ) ) tqFatal ( " Memory technology not defined " ) ;
// packages
for ( TQDomNode child = device . firstChild ( ) ; ! child . isNull ( ) ; child = child . nextSibling ( ) ) {
if ( ! child . isElement ( ) | | child . nodeName ( ) ! = " package " ) continue ;
Package p = processPackage ( child . toElement ( ) ) ;
TQMap < TQString , uint > pinLabels ;
for ( uint i = 0 ; i < uint ( p . pins . count ( ) ) ; i + + ) {
if ( p . pins [ i ] . isEmpty ( ) | | p . pins [ i ] = = " N/C " ) continue ;
TQStringList labels = TQStringList : : split ( " / " , p . pins [ i ] ) ;
for ( uint k = 0 ; k < uint ( labels . count ( ) ) ; k + + ) {
if ( pinLabels . contains ( labels [ k ] ) ) pinLabels [ labels [ k ] ] + + ;
else pinLabels [ labels [ k ] ] = 1 ;
}
}
for ( uint k = 0 ; k < uint ( _data - > _packages . count ( ) ) ; k + + )
for ( uint l = 0 ; l < uint ( p . types . count ( ) ) ; l + + )
for ( uint j = 0 ; j < uint ( _data - > _packages [ k ] . types . count ( ) ) ; j + + )
if ( _data - > _packages [ k ] . types [ j ] = = p . types [ l ] & & _data - > _packages [ k ] . pins . count ( ) = = p . pins . count ( ) ) tqFatal ( " Duplicated package type " ) ;
if ( ! pinLabels . isEmpty ( ) ) checkPins ( pinLabels ) ;
_data - > _packages . append ( p ) ;
}
}
Device : : Package Device : : XmlToDataBase : : processPackage ( TQDomElement element )
{
Package package ;
// nb pins
bool ok ;
uint nb = element . attribute ( " nb_pins " ) . toUInt ( & ok ) ;
if ( ! ok | | nb = = 0 ) tqFatal ( " Malformed \" nb_pins \" " ) ;
package . pins . resize ( nb ) ;
// types
TQStringList types = TQStringList : : split ( " " , element . attribute ( " types " ) ) ;
if ( types . isEmpty ( ) ) tqFatal ( " No package types specified " ) ;
for ( uint k = 0 ; k < uint ( types . count ( ) ) ; k + + ) {
uint i = 0 ;
for ( ; Package : : TYPE_DATA [ i ] . name ; i + + ) {
if ( types [ k ] ! = Package : : TYPE_DATA [ i ] . name ) continue ;
for ( uint j = 0 ; j < uint ( package . types . count ( ) ) ; j + + )
if ( package . types [ j ] = = i ) tqFatal ( TQString ( " Duplicated package type %1 " ) . arg ( types [ k ] ) ) ;
uint j = 0 ;
for ( ; j < Package : : MAX_NB ; j + + )
if ( nb = = Package : : TYPE_DATA [ i ] . nbPins [ j ] ) break ;
if ( j = = Package : : MAX_NB ) tqFatal ( TQString ( " Package %1 does not have the correct number of pins %2 (%3) " ) . arg ( types [ k ] ) . arg ( nb ) . arg ( Package : : TYPE_DATA [ i ] . nbPins [ 0 ] ) ) ;
package . types . append ( i ) ;
break ;
}
if ( Package : : TYPE_DATA [ i ] . name = = 0 ) tqFatal ( TQString ( " Unknown package type \" %1 \" " ) . arg ( types [ k ] ) ) ;
}
// pins
TQString name = Package : : TYPE_DATA [ package . types [ 0 ] ] . name ;
if ( name = = " sot23 " ) {
if ( package . types . count ( ) ! = 1 ) tqFatal ( " SOT23 should be a specific package " ) ;
} else if ( ( nb % 2 ) ! = 0 ) tqFatal ( TQString ( " \" nb_pins \" should be even for package \" %1 \" " ) . arg ( name ) ) ;
uint have_pins = false ;
TQMemArray < bool > found ( nb ) ;
found . fill ( false ) ;
TQDomNode child = element . firstChild ( ) ;
while ( ! child . isNull ( ) ) {
if ( child . nodeName ( ) = = " pin " ) {
if ( ! child . isElement ( ) ) tqFatal ( " \" pin \" is not an element " ) ;
TQDomElement pin = child . toElement ( ) ;
bool ok ;
uint i = pin . attribute ( " index " ) . toUInt ( & ok ) ;
if ( ! ok | | i = = 0 | | i > nb ) tqFatal ( " Malformed pin index " ) ;
if ( found [ i - 1 ] ) tqFatal ( " Duplicated pin index " ) ;
found [ i - 1 ] = true ;
TQString name = pin . attribute ( " name " ) ;
if ( ! name . isEmpty ( ) & & name ! = " N/C " ) {
TQStringList labels = TQStringList : : split ( " / " , name ) ;
if ( name . contains ( " " ) | | labels . count ( ) = = 0 ) tqFatal ( " Malformed pin name " ) ;
if ( name ! = name . upper ( ) ) tqFatal ( " Pin name should be uppercase " ) ;
}
package . pins [ i - 1 ] = name ;
have_pins = true ;
}
child = child . nextSibling ( ) ;
}
if ( ! have_pins ) ; //warning("Pins not specified"); // #### REMOVE ME !!
else for ( uint i = 0 ; i < nb ; i + + ) if ( ! found [ i ] ) tqFatal ( TQString ( " Pin #%1 not specified " ) . arg ( i + 1 ) ) ;
return package ;
}
void Device : : XmlToDataBase : : parse ( )
{
// process device files
TQStringList files ;
TQDir xmlFilesDir ;
if ( ! xmlFolder . isEmpty ( ) )
{
xmlFilesDir . setPath ( xmlFolder ) ;
}
files = xmlFilesDir . entryList ( " *.xml " ) ;
for ( uint i = 0 ; i < uint ( files . count ( ) ) ; i + + ) {
_data = 0 ;
TQDomDocument doc = parseFile ( xmlFilesDir . absFilePath ( files [ i ] ) ) ;
TQDomElement root = doc . documentElement ( ) ;
if ( root . nodeName ( ) ! = " device " ) tqFatal ( " root node should be \" device \" " ) ;
processDevice ( root ) ;
}
// check alternatives
TQMap < TQString , TQStringList > : : const_iterator ait = _alternatives . begin ( ) ;
for ( ; ait ! = _alternatives . end ( ) ; + + ait ) {
TQStringList : : const_iterator lit = ait . data ( ) . begin ( ) ;
for ( ; lit ! = ait . data ( ) . end ( ) ; + + lit )
if ( ! _map . contains ( * lit ) ) tqFatal ( TQString ( " Unknown alternative %1 for device %2 " ) . arg ( ( * lit ) ) . arg ( ait . key ( ) ) ) ;
}
}