Implementierung

Bei der Implementierung eines eigenen Treibers müssen folgende neue Klassen von den im allgemeinen Treiber definierten Klassen abgeleitet werden:

  • MyHWObject (optional, beschreibt die zusätzlichen Eigenschaften spezieller HW-Daten), wird abgeleitet von HWObject.

  • MyHWMapper (in der abgeleiteten Methode actualize(..) wird der Abgleich zwischen Hardwareobjekten und Peripherieadressen durchgeführt, dort muss außerdem eine geeignete Transformation für jedes Hardwareobjekt erzeugt und eingestellt werden), wird von HWMapper abgeleitet.

  • MyDrvResource (optional, dient zur Implementation interner Datenpunkte, sowie zur Erfassung und Verwaltung treiberspezifischer Einstellungen, die abgeleitete Methode readSection() sollte immer auch die Methode commonKeyWord() aufrufen, in der die Ressourcen des allgemeinen Treibers verarbeitet werden), wird abgeleitet von DrvResource.

  • MyHWService (dient der Anbindung an die spezielle Peripherie, berücksichtigt die Kommunikation mit der Hardware, Übertragungsprotokolle, setzt in Befehlsrichtung vorher erzeugte HWObjects an die Peripherie ab, verpackt sie gegebenenfalls in protokollabhängige Telegramme. Behandelt in Melderichtung eintreffende Daten und wandelt diese in HWObjects um, die dann mittels toDp() des DrvManagers in Richtung Eventmanager weitergereicht werden), wird abgeleitet von HWService.

  • MyDrvManager (installiert die speziellen abgeleiteten Objekte des eigenen Treibers, bildet eine Rahmenklasse), wird abgeleitet von DrvManager.

  • MyTransformation (für jede spezielle Datenart der Peripherie muss ein eigenes Transformationsobjekt angelegt werden, das von der Basisklasse Transformation abgeleitet wird).

  • main() (das Hauptprogramm, stellt keine eigene Klasse dar. Ein Objekt MyDrvManager wird erzeugt.)

  • diverse Hilfsobjekte, falls notwendig

Ein typisches Hauptprogramm eines speziellen Treibers kann beispielsweise folgendes Aussehen haben:

// globale Objekte
MyResources resources;
MyDrvManager *g_driver;

// interrupthandler
void sigReceiver( int sigNum )
{
  g_driver->signalHandler( sigNum );
}

int main( int argc, char *argv[] )
{
  MyResources::init( argc, argv );
  if ( Resources::getHelpFlag() )
    MyResources::printHelp();
  else
  {
    g_driver = new MyDrvManager;
    signal( SIGINT, sigReceiver );
    g_driver->mainProcedure( argc, argv );
  }
  return 0;
}

MyResources::init(int argc, char *argv[])
{
  begin(argc,argv[]);
  while (readSection() || generalSection()) ;
  // einlesen der Treiberparameter aus der Konfigurationsdatei
  end(argc, argv);
}

Eine typische Methode workProc() von MyHWService könnte etwa folgendermaßen aussehen:

void MyHWService::workProc()
{
  TimeVar now;
  MyHWObject myObj;
  myObj.setOrgTime(now); // setze Quellzeit
  myObj.setAddress(address); // vereinfachte Annahme: die HWAdresse wird von extern in den String address eingetragen
  HWObject *pDp = DrvManager::getHWMapperPtr()->
  findHWObject(&myObj);
  // suche entsprechendes HWObject im HWMapper
  if (pDp) // gefunden ?
  { 
    // ja
    myObj.setDlen(pDp->getDlen());
    // die Datenlänge wird aus dem HWMapper genommen
    PVSSchar *pBuf = new PVSSchar[myObj.getDlen()];
    // neuen Datenbuffer anlegen
    memcpy(pBuf,dataBuf,myObj.getDlen());
    // Annahme: die Peripheriedaten stehen in dataBuf zur Verfügung
    myObj.setData(pBuf);
    if (data_invalid) // sind die Daten ungültig ?
    myObj.setSbit(DRV_INVALID); // setze invalid-Bit
    DrvManager::getSelfPtr()->toDp(&myObj, pDp);
  }
  else 
    ... // Fehlermeldung
}

Bei dieser Funktion wurde angenommen, dass von der Adresse address (diese entspricht einer parametrierten Peripherieadresse) Daten im Buffer dataBuf (ein char *) anliegen, wobei die Daten ungültig sind, falls das Flag data_invalid (boolean) gesetzt ist.

Die dem entsprechende Funktion writeData(..) des HWService, die Datenpunkte an der Peripherie setzt in Analogie zur obigen Funktion könnte so aussehen:

void writeData(HWObject *myObj)
{
  address = myObj->getAddress();
  // setzt die betroffene Adresse
  memcpy(dataBuf,myObj->getData(),myObj->getDlen());
  // umkopieren der Daten
}

Auch hier wird angenommen, dass die Daten von Adresse address im Buffer dataBuf (der schon existieren muss) zur Verfügung gestellt werden (diesmal von unserem einfachen Treiber). Diese beiden einfachen Funktionen sollen nur den Mechanismus an sich verdeutlichen. Ein echter Treiber könnte sich z.B. in Senderichtung in writeData(..) ein Telegramm zusammenstellen, dass dann über eine TCP-IP Verbindung an einen Partner verschickt wird. In Empfangsrichtung (in der workProc() ) wird ein solches Telegramm interpretiert, die Adresse und die Rohdaten extrahiert und in myObj eingetragen, bevor es mittels toDp(..) dem allgemeinen Treiber weitergereicht wird.