Skip to end of banner
Go to start of banner

Multiple Application / Multiple Device Operation [DE]

Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 48 Current »

Einleitung

Häufig entsteht die Anforderung mehrere COMSOL-Geräte innerhalb einer Applikation anzusprechen oder mit mehreren Applikationen auf ein COMSOL-Gerät zuzugreifen.

Diese Application Note beschreibt die Möglichkeiten und was dabei beachtet werden sollte.

Multiple-Device

Der Zugriff auf mehrere COMSOL-Geräte durch eine Applikation ist problemlos möglich.

Erreicht wird dies durch einen wiederholten Aufruf der xChannelOpen-Funktion und der Parametrierung unterschiedlicher Board-Names.
Der wiederholte Aufruf hat das Generieren eines weiteren Channel-Handles zur Folge; dessen Handling im weiteren Verlauf der Applikation erforderlich ist.
Durch die Auswahl des Handle, bei der Übergabe des hChannel-Parameters in eine der xChannel-Funktionen wird bestimmt, welches Gerät angesprochen wird.

Idealerweise sollte das Prozessdaten-Handling der beiden Geräte, sowie das Handling vom Rest der Applikation entkoppelt sein (Multithreading, Multiprozessing).

Dies wird auch bei einem Single-Device Betrieb empfohlen.

Praxis

Für die Verwendung mehrerer Geräte ist das mehrfache Aufrufen der xChannelOpen-Funktion erforderlich.
Über den szBoard-Parameter können dabei jeweils unterschiedliche Geräte selektiert werden.

Die dabei entstehenden Handles beziehen sich jeweils auf die unterschiedlichen Geräte. Daher sollten diese im weiteren Verlauf der Applikation immer selektiv behandelt werden.

Ein mehrfaches Öffnen des Treibers über xDriverOpen ist nicht erforderlich.

Quellcode
/*****************************************************************************/
/*! Function to handle I/O-data. Using to handle the I/O data from different
*   devices in own threads.
*   Packet Transfer and I/O Data exchange
*   \return CIFX_NO_ERROR on success                                         */
/*****************************************************************************/
DWORD WINAPI IODataHandler(LPVOID hChannel)
{
    long                lRet = CIFX_NO_ERROR;
    /* Read and write I/O data (32Bytes). Output data will be incremented each cyle */
    unsigned char       abRecvData[64] = { 0 };
    unsigned char       abSendData[64] = { 0 };

    /* Do I/O Data exchange until a key is hit */
    while (/* loop condition */)
    {
        if (CIFX_NO_ERROR != (lRet = xChannelIORead(hChannel, 0, 0, sizeof(abRecvData), abRecvData, IO_WAIT_TIMEOUT)))
        {
			...
        }
        if (CIFX_NO_ERROR != (lRet = xChannelIOWrite(hChannel, 0, 0, sizeof(abRecvData), abRecvData, IO_WAIT_TIMEOUT)))
        {
            ...
        }
		...    
    }
}


/*****************************************************************************/
/*! Function to demonstrate communication channel functionality
*   Packet Transfer and I/O Data exchange
*   \return CIFX_NO_ERROR on success                                         */
/*****************************************************************************/
long ChannelDemo(HANDLE hDriver, char* szBoard[], uint32_t ulChannel[], uint32_t channelCount)
{
  HANDLE* hChannels;
  hChannels = malloc(channelCount * 4);

  HANDLE hChannel       = NULL;
  long   lRet           = CIFX_NO_ERROR;

  for (uint32_t i = 0; i < channelCount; i++) {

      printf("---------- Communication Channel demo ----------\r\n");
      lRet = xChannelOpen(hDriver, szBoard, ulChannel, &hChannel);
      if (CIFX_NO_ERROR != lRet)
      {
          printf("Error opening Channel!");
      }
      else
      {
          ...
		  ...
		  ...
		  
		  /* Set Host Ready to signal the filed bus an application is ready */
          lRet = xChannelHostState(hChannel, CIFX_HOST_STATE_READY, &ulState, HOSTSTATE_TIMEOUT);

          if (CIFX_NO_ERROR != lRet)
          {
              printf("Error setting host ready!\r\n");
          }
          else
          {
              /* Switch on the bus if it is not automatically running (see configuration options) */
              lRet = xChannelBusState(hChannel, CIFX_BUS_STATE_ON, &ulState, 0L);

              if (CIFX_NO_ERROR != lRet)
              {
                  printf("Unable to start the filed bus!\r\n");
              }
              else
              {
                  DWORD dwThreadID = 0;
                  hAppThreads[i] = CreateThread( NULL, 0, IODataHandler, hChannels[i], 0, &dwThreadID);
              }
          }
      }

      /* Wait for all threads terminated */
      lRet = WaitForMultipleObjects(channelCount, hAppThreads, TRUE, INFINITE);

      /* Close all Channel-Handler */
      for (uint32_t i = 0; i < channelCount; i++) {
          xChannelClose(ulChannel[i]);
      }
      free(hChannels);

  }
}

Der gezeigte Quellcode, ist Teil aus folgender Demo-Applikation: cifX Demo multiple device

Multiple-Application

Ob der Betrieb mehrerer Applikationen mit einem COMSOL-Device möglich ist, hängt wesentlich vom verwendeten Treiber ab.

Grundsätzlich müssen mehrere Instanzen der Applikation bzw. des Treibers einander bekannt sein, damit Sperrmechanismen für die verwendeten Ressourcen greifen.


Unabhängig vom verwendeten Betriebssystem sollten folgende Faktoren beachtet werden:

Jeder Aufruf der Funktionen xChannelIORead oder xChannelIOWrite zieht automatisch ein Handling der Handshake-Flags nach sich.
Das Handshaking steuert den Zugriff auf das DPM und kann, abhängig vom eingesetzten Protokoll-Stack sowie vom eingestellten Betriebs-Modi, synchron zum Buszyklus sein.
Ein erneuter Aufruf der Funktion wäre in diesem Fall ein "blockender" Aufruf.

Erst mit dem nächsten Buszyklus und dem toggeln des Handshake wird die Funktion beendet und ein Wert zurückgegeben.
Der Wert stammt in diesem Fall jedoch nicht mehr aus demselben Buszyklus.

Umgekehrt ist bei einem asynchronen Betrieb völlig unklar, ob die Werte zweier Calls der xChannelIORead/Write-Funktionen, aus unterschiedlichen oder demselben Buszyklus stammen.

Grundsätzlich wäre also der Einsatz eines Datenproviders, der das Handling der Prozessdaten direkt an der CIFX API übernimmt und die Informationen an die jeweiligen Applikationen verteilt bzw. entgegennimmt, zu empfehlen.

Windows

Beim Windows Treiber sind die wesentlichen Bestandteile des Treibers im Kernel-Space implementiert.

Der Teil des Treibers der die relevanten Ressourcen schützt, wird also nicht in mehreren Prozessen gestartet.

Dadurch ist ein Betrieb mehrerer Applikationen, die auf eine CifX-Karte zugreifen, also grundsätzlich möglich.

Linux

Im Standard Linux-Treiber ist der Signifikate Teil des Treibers als Userspace-Modul ausgelegt.

Jede Instanz des Treibers bzw. einer Applikation läuft in einem eigenen Prozess. Da keine Interprozesskommunikation im Treiber implementiert ist, funktionieren die Schutzvorkehrungen der Ressourcen nicht über mehrere Treiber-Instanzen hinweg.

Von Haus aus ist ein Betrieb mehrerer Applikationen also nicht möglich.



  • No labels