Da habe ich die Bibliothek unter IEC 870-5-104 auf Arduino mit Wireshark geschrieben

In diesem Artikel möchte ich über meine Bekanntschaft mit dem IEC 870-5-104-Datenübertragungskanal seitens eines gesteuerten (Slave-) Geräts sprechen, indem ich eine einfache Bibliothek in Arduino schreibe.

Was ist IEC 870-5-104 und wo wird es verwendet?


IEC 60870-5-104 ist ein Telemechanikprotokoll zur Übertragung von TM-Signalen an ASTU, das die Verwendung des Netzwerkzugriffs über TCP / IP regelt. Es wird im Energiesektor am häufigsten zum Informationsaustausch zwischen Energiesystemen sowie zum Empfangen von Daten von Messwandlern (Voltmeter, Stromzähler usw.) verwendet.

Protokollstack IEC 670-5-104:



Verwendete Materialien


  • Arduino UNO Board
  • Ethernet-Abschirmung (HR911105a);
  • Microscada von ABB fungiert als Master für IEC 60870-5-104.
  • Wireshark für die Verkehrsanalyse.


Eine kurze Beschreibung der Arbeitsschritte


  1. Installieren Sie die TCP / IP-Verbindung an Port 2404;
  2. Bestätigung einer Anfrage zur Datenübertragung (STARTDT act / con);
  3. Bitte um einen allgemeinen Überblick über die Station;
  4. Vorbereitung und Übertragung von Daten an die Master-Station;
  5. Testverfahren

Vorbereitung


  • Arduino-Karte an PC angeschlossen;
  • Die Netzwerkschnittstelle ist entsprechend konfiguriert.
  • Eine Master-Station wurde konfiguriert (104 Leitungen wurden hinzugefügt und ein Slave-Gerät wurde hinzugefügt).



Begriffe und Abkürzungen


APCI - Application Level Control Information kann als eigenständiger Steuerrahmen (U-Frame oder S-Frame) verwendet werden.
ASDU - Datenblöcke auf Anwendungsebene, bestehen aus einer Datenblockkennung und einem oder mehreren Informationsobjekten, die jeweils ein oder mehrere homogene Informationselemente (oder Kombinationen von Informationselementen) enthalten.
APDU - Protokolldateneinheit der Anwendungsschicht.
TS - Fernalarm.
TI - Telemetrie.
TU - Fernbedienung.

1. Stellen Sie den TCP / IP-Verbindungsport 2404 her


Eine Hauptstation initiiert eine TCP-Verbindung, indem sie ein TCP-Paket mit einem Flag (SYS) sendet. Eine Verbindung gilt als hergestellt, wenn die überwachte Station (Slave) während der Überwachungszeit (t0) auf ihrer TCP / IP-Ebene eine "Active Open" -Bestätigung (SYS ACK) ausgestellt hat. Die Steuerzeit t0 wird als "Verbindungsaufbau-Timeout" bezeichnet. Der Zeitgeber t0 bestimmt, wann das Öffnen abgebrochen wird, und bestimmt nicht den Beginn eines neuen Verbindungsversuchs.



Die Interaktion mit der Transportschicht wird von der Standardbibliothek für Arduino Ethernet.h-Karten ausgeführt. Das heißt, zunächst muss eine TCP / IP-Verbindung zwischen der gesteuerten Station und der Überwachungsstation hergestellt werden. Dazu initialisieren Sie in der Arduino-Skizze das Gerät und erstellen einen Server, der auf eingehende Verbindungen über den angegebenen Port wartet.

Skizze
#include 
byte mac[] = {0x90, 0xA2, 0xDA, 0x0E, 0x94, 0xB7 };//мак адрес 
IPAddress ip(172, 16, 7, 1);// ip адрес контролируемого устройства
IPAddress gateway(172, 16,7, 0);//шлюз
IPAddress subnet(255, 255, 0, 0);//маска
EthernetClient client;
EthernetServer iec104Server(2404);// для МЭК 670-5-104- порт- 2404
void setup()
{
  Ethernet.begin(mac, ip, gateway, subnet); // инициализация Ethernet-устройства
}
void loop()
{
  client = iec104Server.available();//подсоединение клиентов 
}


Wenn Sie diese Skizze herunterladen, geschieht Folgendes: Wenn



eine Verbindung hergestellt wird, wird das für Arduino unbekannte Paket STARTDT act ausgeführt und nach einer bestimmten Zeit wird die Verbindung getrennt. Als nächstes müssen Sie verstehen, was STARTDT ist.

2. Bestätigung einer Anfrage zur Datenübertragung (STARTDT act / con)


In IEC 670-5-104 gibt es drei Arten von Formaten für die Übertragung:

  • I-Format zur Übertragung von Telemetriedaten;
  • S-Format zur Übermittlung von Belegen;
  • U-Format zur Übertragung von Kommunikationsaufbaupaketen und zum Testen von Kommunikationskanälen.

Nach einem erfolgreichen „Triple Handshake“ sendet die Masterstation eine APDU STARTDT (Data Transfer Start). STARTDT veranlasst für die gesteuerte (Slave-) Station die Übertragung von ASDUs (Frames I) in Richtung des steuernden (Master-), um den Betrieb fortzusetzen. STARTDT muss bestätigt werden, wenn die gesteuerte (Slave-) Station bereit ist, Datenblöcke zu senden. Wenn die Slave-Station den STARTDT nicht bestätigt, bewirkt die Master-Station, dass die IP-Verbindung geschlossen wird.

Bild


Daher ist es weiterhin erforderlich, die von der steuernden (Master-) Station empfangenen Bytes zu lesen und zu analysieren.

Skizze
uint8_t iec104ReciveArray[128];//массив для приема 
EthernetClient client = iec104Server.available();
 if(client.available())
  {
    delay(100);
    int i = 0;
while(client.available())
 {
    iec104ReciveArray[i] = client.read();//записываем в буфер приема данные
    i++;
 }


Nachdem Sie die Daten gelesen haben, müssen Sie sie analysieren und eine Antwort bilden.

Wireshark


Das Paket mit dem STARTDT-Block in Wireshark sieht folgendermaßen aus: Die APDU ist ein U-Block, der nur aus APCI besteht.
APCI - Application Level Control Information kann als eigenständiger Steuerrahmen (U-Frame oder S-Frame) verwendet werden.



Kurz gesagt, die APCI bestimmt den Typ der APDU und ihre Länge. APCI besteht aus den folgenden sechs Bytes:

1. Ein Initialisierungsflag einer APDU variabler Länge, beginnend mit Byte START2 68h;
2. Die Länge der APDU beträgt in diesem Beispiel vier Bytes.
3. In das Steuerbyte, in dem der APDU-Typ festgelegt ist, wird in diesem Beispiel ein Wert von sieben geschrieben, was eine Anforderung zur Datenübertragung bedeutet;
4,5,6 Nicht verwendet.



Basierend auf dem oben Gesagten würde es nicht schaden, vor der Beantwortung festzustellen, welchen APDU-Typ die Überwachungsstation an uns gesendet hat. In dem Wissen, dass der APDU-Typ in der dritten Bytereihenfolge des Lesens des APCI-Blocks geschrieben ist, werde ich ihn in einer Ganzzahlvariablen speichern.
Hinweis: Wenn ein Paket des Formats "I" empfangen wird, enthalten 3 Byte in der APCI auch den Wert des niedrigen Wortes des Zählers der empfangenen Pakete. Daher musste

ich den Entwurf zur Bestimmung des APDU-Typs etwas komplizieren.

Skizze
ASDU=iec104ReciveArray[6];//пакет ASDU?
    switch (ASDU)
   {
    case 100://опрос станции
    TypeQuerry=iec104ReciveArray[2]-word(iec104ReciveArray[3],iec104ReciveArray[2]);//Тип 
    rxcnt+=2;//увеличение счетчика принятых пакетов 
    break;
    case 0:
    TypeQuerry=iec104ReciveArray[2]; //Тип 
    break;
    default :
    TypeQuerry=iec104ReciveArray[2];//Тип
    break;
   }      



Aus der obigen Abbildung ist ersichtlich, dass der APDU-Typ, der dem Wert 7 entspricht, STARTDT act ist, dementsprechend muss mit demselben Paket in der Struktur geantwortet werden, nur der Typwert muss den Wert 11 (0b) haben, der STARTDT con entspricht.

Skizze
#include 
byte mac[] = {0x90, 0xA2, 0xDA, 0x0E, 0x94, 0xB7 };
IPAddress ip(172, 16, 7, 1);
IPAddress gateway(172, 16,7, 0);
IPAddress subnet(255, 255, 0, 0);
EthernetClient client;
EthernetServer iec104Server(2404);
int TypeQuerry, MessageLength;// тип APDU и длина посылки
uint8_t iec104ReciveArray[128];//буфер приема APDU
void setup()
{
  Ethernet.begin(mac, ip, gateway, subnet);
}
void loop()
{
  client = iec104Server.available();
  if(client.available())//клиент подсоединен
   {
     delay(100);
     int i = 0;
     while(client.available())//чтение байтов
     {
       iec104ReciveArray[i] = client.read();//записываем в буфер приема данные
       i++;
     }
    TypeQuerry= iec104ReciveArray[2];//определяем тип APDU
    switch(TypeQuerry)
  {
       case 07:// если пришел тип STARTDT
       iec104ReciveArray[0]=iec104ReciveArray[0];// START2 = 68h;
       iec104ReciveArray[1]=iec104ReciveArray[1];//длина APDU 
       iec104ReciveArray[2] = iec104ReciveArray[2]+4; //тип APDU
       iec104ReciveArray[3]=0;
       iec104ReciveArray[4]=0;
       iec104ReciveArray[5]=0;
       MessageLength = iec104ReciveArray[1]+2;//длина сообщения + 2 байта Start and Lenght APCI
       delay(100);
       client.write(iec104ReciveArray, MessageLength);//передача обратно
    break;
  }
 }
}


Nach der Aktualisierung der Skizze das folgende Verfahren für den Austausch beachten:



der Verbindungsaufbau, die Anforderung für die Datenübertragung, Anfrage und bestätigt wieder einen neuen noch unbekannten APDU Format Typen I 1 C_IC_NA Act.

3. Fordern Sie eine allgemeine Stationsbesichtigung an


Das Abfrageteam C_IC ACT fordert das vollständige Volumen oder eine bestimmte Teilmenge der abgefragten Informationen an den CP an. Eine Untermenge (Gruppe) wird unter Verwendung des QOI-Abfragedeskriptors ausgewählt.
Das Stationsabfrageteam fordert die Stationen auf, den aktuellen Status ihrer Informationen, normalerweise sporadisch übertragen (Übertragungsgrund = 3), an die Überwachungsstation mit Übertragungsgründen von <20> bis <36> zu senden. Die Stationsabfrage wird verwendet, um Prozessinformationen an einer steuernden Station und an gesteuerten Stationen zu synchronisieren. Es wird auch verwendet, um Informationen in der Überwachungsstation nach dem Initialisierungsvorgang oder nachdem die Überwachungsstation einen Kanalverlust (erfolglose Wiederholung der Verbindungsschichtanforderung) und dessen anschließende Wiederherstellung festgestellt hat, zu aktualisieren. Die Antwort auf die Stationsabfrage sollte Prozessinformationsobjekte enthalten, die in der überwachten Station gespeichert sind. In Reaktion auf die Stationsabfrage werden diese Informationsobjekte mit Kennungen der Typen <1>, <3>, <5>, <7>, <5> übertragen

Bild



APDU <100> C_IC_NA_1 verfügt neben dem APCI-Block auch über einen ASDU-Block (Application Layer Data Block), die zusammen die APDU Protocol Data Unit bilden.



Betrachten Sie die resultierende APDU genauer.

APCI:

  • Das erste Byte gibt den Typ 0 an. Dies bedeutet, dass es sich um einen Abrufbefehl handelt.
  • In der zweiten ist die Länge der APDU 14 Bytes;

ASDU:

  • Das erste Byte in der ASDU bestimmt den Typ des Informationsobjekts, in diesem Fall <100> C_IC_NA_1 (General Station Polling);
  • Die zweite Struktur des Datenblocks;
  • Der dritte Grund für die Übertragung (CauseTx), ein Wert von sechs, bedeutet eine Aktivierungsanforderung.
  • Die vierte gemeinsame Adresse des Landes;
  • Fünfte Adresse der Slave-Station;
  • Von der sechsten bis zur achten Adresse des Informationsobjekts ist Null;
  • Neuntes Informationsbyte - QOI - Anforderungsdeskriptor mit folgenden Werten:

In Antwort auf <100> C_IC_NA_1 muss auf die Anfrage mit einer Bestätigung geantwortet, die auf der überwachten Station abgelegten Prozessinformationsobjekte übertragen und die Aktivierung abgeschlossen werden.
Um eine Bestätigung zu senden, muss in ASDU <100> C_IC_NA_1 ein Byte geschrieben werden, das den Grund für die Übertragung angibt (CauseTX), ein Wert von 7, und um einen Aktivierungsabschluss zu senden, muss ein Byte geschrieben werden, das den Grund für die Übertragung angibt (CauseTX), der 10 entspricht.

Skizze
      case 00://опрос станции 
      txcnt=txcnt+02;
      //Подтверждение общего опроса 
      iec104ReciveArray[0]=iec104ReciveArray[0];
      iec104ReciveArray[1]=iec104ReciveArray[1];
      iec104ReciveArray[2]=lowByte(txcnt);//TX L
      iec104ReciveArray[3]=highByte(txcnt);//TX H
      iec104ReciveArray[4]=lowByte(rxcnt);//RX L
      iec104ReciveArray[5]=highByte(rxcnt);//RX H
      iec104ReciveArray[6]=100;//опрос станции
      iec104ReciveArray[7]=01;
      iec104ReciveArray[8]=7;//cause Actcon
      iec104ReciveArray[9]=00;//OA
      iec104ReciveArray[10]=01;//Addr
      iec104ReciveArray[11]=00;//Addr
      iec104ReciveArray[12]=00;//IOA
      iec104ReciveArray[13]=00;//IOA
      iec104ReciveArray[14]=00;//IOA
      iec104ReciveArray[15]=20;//IOA, QOI
      MessageLength = iec104ReciveArray[1]+2;
      delay(100);
      client.write(iec104ReciveArray, MessageLength); 
      txcnt=txcnt+2;//увеличение счетчика переданных пакетов
    //актуальные состояния информации контролирующей станции в ответ на общий опрос 
      iec104ReciveArray[0]=iec104ReciveArray[0];
      iec104ReciveArray[1]=14;//длина  APDU=APCI(4)+ ASDU(10)
      iec104ReciveArray[2]=lowByte(txcnt);
      iec104ReciveArray[3]=highByte(txcnt);
      iec104ReciveArray[4]=lowByte(rxcnt);
      iec104ReciveArray[5]=highByte(rxcnt);
      iec104ReciveArray[6]=1;//type 1
      iec104ReciveArray[7]=01;//sq
      iec104ReciveArray[8]=20;//Cause Inrogen
      iec104ReciveArray[9]=00;//AO
      iec104ReciveArray[10]=01;//Adress
      iec104ReciveArray[11]=00;//Adress
      iec104ReciveArray[12]=iecData[0];//IOA
      iec104ReciveArray[13]=iecData[1];//IOA
      iec104ReciveArray[14]=0;//IOA
      iec104ReciveArray[15]=iecData[2];//value [DATA 1]
      MessageLength = iec104ReciveArray[1]+2;
      client.write(iec104ReciveArray, MessageLength); 
      txcnt=txcnt+2;
      iec104ReciveArray[0]=iec104ReciveArray[0];
      iec104ReciveArray[1]=14;
      iec104ReciveArray[2]=lowByte(txcnt);
      iec104ReciveArray[3]=highByte(txcnt);
      iec104ReciveArray[4]=lowByte(rxcnt);
      iec104ReciveArray[5]=highByte(rxcnt);
      iec104ReciveArray[6]=1;//type 1 bool
      iec104ReciveArray[7]=01;
      iec104ReciveArray[8]=20;//Cause Inrogen
      iec104ReciveArray[9]=00;
      iec104ReciveArray[10]=01;
      iec104ReciveArray[11]=00;
      iec104ReciveArray[12]=iecData[3];
      iec104ReciveArray[13]=iecData[4];
      iec104ReciveArray[14]=0;
      iec104ReciveArray[15]=iecData[5];
      MessageLength = iec104ReciveArray[1]+2;
      client.write(iec104ReciveArray, MessageLength); 
      delay(5);
      txcnt=txcnt+2;
      iec104ReciveArray[0]=iec104ReciveArray[0];
      iec104ReciveArray[1]=22; 
      iec104ReciveArray[2]=lowByte(txcnt);
      iec104ReciveArray[3]=highByte(txcnt);
      iec104ReciveArray[4]=lowByte(rxcnt);
      iec104ReciveArray[5]=highByte(rxcnt);
      iec104ReciveArray[6]=11;//type 11 int
      iec104ReciveArray[7]=02;//sq
      iec104ReciveArray[8]=20;//Cause Inrogen
      iec104ReciveArray[9]=00;//AO
      iec104ReciveArray[10]=01;//Adress
      iec104ReciveArray[11]=00;//Adress
      iec104ReciveArray[12]=iecData[6];//IOA
      iec104ReciveArray[13]=iecData[7];//IOA
      iec104ReciveArray[14]=0;//IOA
      iec104ReciveArray[15]=iecData[8];//value [DATA 1]
      iec104ReciveArray[16]=iecData[9];//value [DATA 1] 
      iec104ReciveArray[17]=iecData[10];//QDS 
      iec104ReciveArray[18]=iecData[11];//IOA
      iec104ReciveArray[19]=iecData[12];//OA
      iec104ReciveArray[20]=0;//IOA
      iec104ReciveArray[21]=iecData[13];//value  [DATA 2]
      iec104ReciveArray[22]=iecData[14];//value  [DATA 2]
      iec104ReciveArray[23]=iecData[15];//IOA QDS 
      MessageLength = iec104ReciveArray[1]+2;
      client.write(iec104ReciveArray, MessageLength);
      delay(5);
      txcnt=txcnt+2;
      iec104ReciveArray[0]=iec104ReciveArray[0];
      iec104ReciveArray[1]=26; 
      iec104ReciveArray[2]=lowByte(txcnt);
      iec104ReciveArray[3]=highByte(txcnt);
      iec104ReciveArray[4]=lowByte(rxcnt);
      iec104ReciveArray[5]=highByte(rxcnt);
      iec104ReciveArray[6]=13;//type 13 Float
      iec104ReciveArray[7]=02;//sq
      iec104ReciveArray[8]=20;//Cause Inrogen
      iec104ReciveArray[9]=00;//AO
      iec104ReciveArray[10]=01;//Adress
      iec104ReciveArray[11]=00;//Adress
      iec104ReciveArray[12]=iecData[16];//IOA
      iec104ReciveArray[13]=iecData[17];//IOA
      iec104ReciveArray[14]=0;
      iec104ReciveArray[15]=iecData[18];//value [DATA 1]
      iec104ReciveArray[16]=iecData[19];//value [DATA 1]
      iec104ReciveArray[17]=iecData[20];//value [DATA 1]
      iec104ReciveArray[18]=iecData[21];//value [DATA 1]
      iec104ReciveArray[19]=iecData[22];//IOA QDS
      iec104ReciveArray[20]=iecData[23];//IOA
      iec104ReciveArray[21]=iecData[24];//IOA
      iec104ReciveArray[22]=0;//IOA
      iec104ReciveArray[23]=iecData[25];//value [DATA 2]
      iec104ReciveArray[24]=iecData[26];//value [DATA 2]
      iec104ReciveArray[25]=iecData[27];//value [DATA 2]
      iec104ReciveArray[26]=iecData[28];//value [DATA 2]
      iec104ReciveArray[27]=iecData[29];//IOA QDS 
      MessageLength = iec104ReciveArray[1]+2;
      client.write(iec104ReciveArray, MessageLength);
      txcnt=txcnt+2;
    //Завершение общего опроса
      iec104ReciveArray[0]=iec104ReciveArray[0];
      iec104ReciveArray[1]=iec104ReciveArray[1];
      iec104ReciveArray[2]=lowByte(txcnt);
      iec104ReciveArray[3]=highByte(txcnt);
      iec104ReciveArray[4]=lowByte(rxcnt);
      iec104ReciveArray[5]=highByte(rxcnt);
      iec104ReciveArray[6]=100;//type
      iec104ReciveArray[7]=01;//sq
      iec104ReciveArray[8]=10;//cause AckTerm
      iec104ReciveArray[9]=00;
      iec104ReciveArray[10]=01;
      iec104ReciveArray[11]=00;
      iec104ReciveArray[12]=00;
      iec104ReciveArray[13]=00;
      iec104ReciveArray[14]=00;
      iec104ReciveArray[15]=20;
      MessageLength = iec104ReciveArray[1]+2;
      client.write(iec104ReciveArray, MessageLength);
      iec104ReciveArray[6]=00;//сброс для нормальног определения нового входящего пакета
    break;


Nach dem Aktualisieren der Skizze beobachten wir folgende Reihenfolge:


Verbindungsaufbau, Datenübertragung anfordern, Bestätigung, Anforderung eines allgemeinen Stationsabrufs von der steuernden Station, Abschluss der Initialisierung, Anforderung eines allgemeinen Stationsabrufs in Richtung der gesteuerten Station, Bestätigung eines allgemeinen Abrufs, Senden der Werte aller verfügbaren Signale an die Station der Überwachung und das allgemeine Umfrage unbekanntes Format APCI S. Abschluss
anfordern Wahllokal in einer Richtung gesteuerten Station ausgegeben:
- wenn von der überwachten Station „empfängt K Heff Initialization „oder
- wenn die Zentralstation feststellt, den Verlust des Kanals (Kanal - Ebene Abfrage erfolglos Wiederholung) und deren anschließenden Gewinnung.

4. Vorbereitung und Datenübertragung


APDU S-Format-Einheit, die nur aus APCI besteht, soll das angenommene APDU I-Format bestätigen. Für das S-Format werden die 7 hohen Bits des Servicefeldes von Byte 1 und Byte 2 nicht verwendet, und Byte 3 (7 hohe Bits) und Byte 4 bestimmen die aktuelle Nummer der empfangenen Nachricht.



In diesem Fall zeigt Block S an, dass die steuernde (Master-) Station bereit ist, Daten innerhalb einer bestimmten Zeit zu empfangen, wobei die auf der Seite der steuernden (Master-) Station festgelegte Zeit t3 nicht überschritten wird. Das heißt, die Hauptstation sagt uns, "Ich bin bereit, Daten zu empfangen!" Als Nächstes müssen Sie sich darum kümmern, welche Daten übertragen werden und woher sie stammen.

Was kann übertragen werden? In IEC 870-5-104 sind verschiedene Arten von Informationen definiert:

  • Kontrolle;
  • Manager;
  • Parameter;
  • Dateiübertragung.

Bild


In diesem Beispiel wird die Übertragung von Steuerinformationen am Beispiel von 1, 11 und 13 Funktionen (Einzelelement, Messung ist skalierbar, Messung ist Kurzformat mit Gleitkomma) betrachtet. Daten werden zufällig generiert. Es ist auch zu berücksichtigen, dass jedes übertragene Signal ein Qualitätsbyte aufweist.



Ein einfacher Algorithmus zur Bestimmung der Signalqualität:

  • Wenn die Ersetzung des aktiven Signals verwendet wird, werden die Flags BL (Blockierung) und SB (Ersetzung) gesetzt.
  • Wenn sich der Signalwert während der Steuerperiode nicht geändert hat, wird das NT-Flag gesetzt (nicht relevant);
  • Wenn Anzeichen für eine Inoperabilität eines Knotens oder Geräts einer niedrigeren Ebene (Sensor oder anderes) vorliegen, wird das Flag IV gesetzt (kein zuverlässiger Wert).

Skizze
void SetQDS(int currvalue, int i,bool zam)//определение качества сигнала
{
if (zam==0)//замещение?
{
  if (currvalue==previusValue[i])//значение не изменялось?
    {
      previusValue[i]=currvalue;
      counter[i]+=1;
      if (counter[i]>=1000)
        {
          qds[i]=64;// NT 
          counter[i]=0;
        }
    }
    else
    {
        qds[i]=0;
        counter[i]=0;
        previusValue[i]=currvalue;
    }
}
else 
  {
    qds[i]=48;// SB, BL   
  }
}


Es muss auch berücksichtigt werden, dass für jedes Signal eine eindeutige IOA-Kennung vorhanden ist. In der Energiewirtschaft ist es üblich, diese Adressen wie folgt zu verteilen:

  • TS-ab 4096;
  • TI-Start bei 8192;
  • TU-ab 20480.

Verwenden Sie die EEPROM-Bibliothek, um den Signalwert zum Senden an das Array zu übertragen:

Skizze
void EEPROM_float_write(int addr, float val,int IOA,int number,bool subs) // начальный адрес в EEPROM, значение сигнала, адрес сигнала, порядковый номер измеряемого сигнала, замещение
{  
  SetQDS(val,number, subs);//установка качества сигнала
  byte *x = (byte *)&val;//float -->byte
  byte *xxx = (byte *)&IOA;//запись адреса IOA
  for(int jj = 0; jj <2; jj++)
    {
      EEPROM.write(addr,xxx[jj]);//сохранение в EEPROM адреса блока данных в 2 байтах
      addr+=1;
    }
  for(byte i = 0; i < 4; i++) //запись формата float в 4 байтах
    {
      EEPROM.write(addr, x[i]); //запись формата float в 4 байтах
      addr+=1;
    }
  EEPROM.write(addr, qds[number]);//запись информации о качестве сигнала
  if (addr == EEPROM.length())
    {
      addr = 0;
    }
}


Nachdem Sie die APDU-Bestätigung im S- oder I-Format von der Überwachungsstation erhalten haben, können Sie mit der Übertragung der verfügbaren Daten beginnen, ohne zu vergessen, die Nummer des übertragenen Frames zu erhöhen.


Skizze
#include 
#include 
#include 
byte mac[] = {0x90, 0xA2, 0xDA, 0x0E, 0x94, 0xB7 };
IPAddress ip(172, 16, 7, 1);
IPAddress gateway(172, 16,7, 0);
IPAddress subnet(255, 255, 0, 0);
EthernetClient client;
EthernetServer iec104Server(2404);
int TypeQuerry, MessageLength;
uint8_t iec104ReciveArray[128];
int counter[6];//порядковый номер сигнала
int qds[6];//порядковый номер для определения качества сигнала
int previusValue[6];//порядковый номер для определения статуса NT
word iecData[256];//буфер для хранения значений сигналов
int ASDU;//для определения типа входящего пакета
int txcnt, rxcnt;//счетчики переданных и принятых пакетов
void setup()
{
  //создание сервера 2404 порт
  Ethernet.begin(mac, ip, gateway, subnet);
  Serial.begin(9600);
 }
 void EEPROM_float_write(int addr, float val,int IOA,int number,bool zam) // запись в ЕЕПРОМ значения типа Float функция 13
{  
  SetQDS(val,number,zam);//качество сигнала  
  byte *x = (byte *)&val;
  byte *xxx = (byte *)&IOA;
  for(int jj = 0; jj <2; jj++)//запись адреса IOA в 2 байта
    {
      EEPROM.write(addr,xxx[jj]);
      addr+=1;  
    }
  for(byte i = 0; i < 4; i++)//запись формата float в 4 байта 
  {
      EEPROM.write(addr, x[i]);
      addr+=1;
  }
      EEPROM.write(addr, qds[number]);
     if (addr == EEPROM.length())
       {
          addr = 0;
       }
}
void EEPROM_byte_write(int addr, bool val,int IOA,int number,bool zam) // запись в ЕЕПРОМ значения типа Bool функция 1
{  
  SetQDS(val,number,zam);//качество сигнала  
  byte c=val+qds[number];
  byte *x = (byte *)&c;
  byte *xxxx = (byte *)&IOA;
  for(int jj = 0; jj <2; jj++) //запись адреса IOA в 2 байта
    { 
      EEPROM.write(addr,xxxx[jj]);
      addr+=1;  
    }
  for(byte i = 0; i < 1; i++) //запись формата bool + качество сигнала в 1 байт 
  {
  EEPROM.write(addr, x[i]);
  }
  if (addr == EEPROM.length()) {
    addr = 0;
  }
}
void EEPROM_int_write(int addr, int val, int IOA,int number,bool zam) // запись в ЕЕПРОМ значения типа Int функция 11
{ 
  SetQDS(val,number,zam); //качество сигнала 
  byte *x = (byte *)&val;
  byte *xx = (byte *)&IOA;
  for(int jj = 0; jj <2; jj++)//запись адреса IOA в 2 байта
    {
      EEPROM.write(addr,xx[jj]);
      addr+=1;  
    }
    for(byte i = 0; i < 2; i++)//запись формата int  в 2 байтa
  {
  EEPROM.write(addr, x[i]);
   addr+=1; 
  }
   EEPROM.write(addr, qds[number]);
     if (addr == EEPROM.length()) {
    addr = 0;
  }
}
//установка качества сигнала
void SetQDS(int currvalue, int i,bool zam)//текущее значение, порядковый номер измеряемого сигнала, замещение
{
if (zam==0)//замещение?
{
  if (currvalue==previusValue[i])//значение не изменялось?
    {
      previusValue[i]=currvalue;
      counter[i]+=1;
      if (counter[i]>=1000)
        {
          qds[i]=64;//установка флага NT
          counter[i]=0;
        }
      }
    else
      {
        qds[i]=0;
        counter[i]=0;
        previusValue[i]=currvalue;
      }
}
else 
  {
          qds[i]=48;//установка флагов замещение и блокировки
  }
}
void loop()
{ 
//Тестовые данные для 1,11,13 функций
//в формате: (адрес в EEPROM, значение сигнала, IOA адрес, качество сигнала)
   EEPROM_byte_write(0,0,4096,0,0);
   EEPROM_byte_write(3,random(0, 2),4097,1,1);  
   EEPROM_int_write(6,  67,8192,2,1);
   EEPROM_int_write(11, random(10, 20),8193,3,0);
   EEPROM_float_write(16, random(-1000, 2000),8194,4,1);
   EEPROM_float_write(23, 78.66f,8195,5,1);
   client = iec104Server.available();
if(client.available())
  {
    delay(100);
    int i = 0;
    while(client.available())
    {
    iec104ReciveArray[i] = client.read();//записываем в буфер приема данные
    i++;
    }
    ASDU=iec104ReciveArray[6];//пакет ASDU?
    switch (ASDU)
   {
    case 100://опрос тсанции
    TypeQuerry=iec104ReciveArray[2]-word(iec104ReciveArray[3],iec104ReciveArray[2]);
    rxcnt+=2;//увеличение счетчика принятых пакетов 
    break;
    case 0:
    TypeQuerry=iec104ReciveArray[2];//определяем тип посылки  
    break;
    default :
    TypeQuerry=iec104ReciveArray[2];
    break;
   }      
    for(byte z = 0; z <64; z++)   //чтение из еепром 
    {
      iecData[z]= EEPROM.read(z);
    }
 //Тип принятого APDU
  switch(TypeQuerry)
  {
    case 07://APDU STARTDT
       rxcnt=0;
       txcnt=0;
       iec104ReciveArray[0]=iec104ReciveArray[0];//кадр переменной длины, начинающийся байтом START2 = 68h;
       iec104ReciveArray[1]=iec104ReciveArray[1];//длина APDU 
       iec104ReciveArray[2]=11;//STARTDT con
       iec104ReciveArray[3]=0;
       iec104ReciveArray[4]=0;
       iec104ReciveArray[5]=0;
       MessageLength = iec104ReciveArray[1]+2;//длина пакета
       client.write(iec104ReciveArray, MessageLength);//отправка обратно
      //Инициализация
      iec104ReciveArray[0]=iec104ReciveArray[0];//кадр переменной длины, начинающийся байтом START2 = 68h;
      iec104ReciveArray[1]=14;//длина APDU
      iec104ReciveArray[2]=0;//тип, TX L
      iec104ReciveArray[3]=0;//TX H
      iec104ReciveArray[4]=0;//RX L
      iec104ReciveArray[5]=0;//RX H
      iec104ReciveArray[6]=70;//type End of Init
      iec104ReciveArray[7]=01;//sq
      iec104ReciveArray[8]=04;//cause Init
      iec104ReciveArray[9]=00;//AO
      iec104ReciveArray[10]=01;//Adress
      iec104ReciveArray[11]=00;//Adress
      iec104ReciveArray[12]=00;//IOA
      iec104ReciveArray[13]=00;//IOA
      iec104ReciveArray[14]=00;//IOA
      iec104ReciveArray[15]=129;//IOA, COI
      MessageLength = iec104ReciveArray[1]+2;
      client.write(iec104ReciveArray, MessageLength);
     //Общий опрос в направление контролируемой станции 
      iec104ReciveArray[0]=iec104ReciveArray[0];
      iec104ReciveArray[1]=14;//длина APDU
      iec104ReciveArray[2]=2;//TX L
      iec104ReciveArray[3]=0;//TX H
      iec104ReciveArray[4]=0;//RX L
      iec104ReciveArray[5]=0;//RX H
      iec104ReciveArray[6]=100;// опрос станции
      iec104ReciveArray[7]=01;
      iec104ReciveArray[8]=6;//cause Act
      iec104ReciveArray[9]=00;
      iec104ReciveArray[10]=01;
      iec104ReciveArray[11]=00;
      iec104ReciveArray[12]=00;
      iec104ReciveArray[13]=00;
      iec104ReciveArray[14]=00;
      iec104ReciveArray[15]=20;//IOA, QOI общий
      MessageLength = iec104ReciveArray[1]+2;
      client.write(iec104ReciveArray, MessageLength); 
      txcnt=txcnt+02;
      break;
      case 00://опрос станции 
      txcnt=txcnt+02;
      //Подтверждение общего опроса 
      iec104ReciveArray[0]=iec104ReciveArray[0];
      iec104ReciveArray[1]=iec104ReciveArray[1];
      iec104ReciveArray[2]=lowByte(txcnt);//TX L
      iec104ReciveArray[3]=highByte(txcnt);//TX H
      iec104ReciveArray[4]=lowByte(rxcnt);//RX L
      iec104ReciveArray[5]=highByte(rxcnt);//RX H
      iec104ReciveArray[6]=100;//опрос станции
      iec104ReciveArray[7]=01;
      iec104ReciveArray[8]=7;//cause Actcon
      iec104ReciveArray[9]=00;//OA
      iec104ReciveArray[10]=01;//Addr
      iec104ReciveArray[11]=00;//Addr
      iec104ReciveArray[12]=00;//IOA
      iec104ReciveArray[13]=00;//IOA
      iec104ReciveArray[14]=00;//IOA
      iec104ReciveArray[15]=20;//IOA, QOI
      MessageLength = iec104ReciveArray[1]+2;
      delay(100);
      client.write(iec104ReciveArray, MessageLength); 
      txcnt=txcnt+2;//увеличение счетчика переданных пакетов
    //актуальные состояния информации контролирующей станции в ответ на общий опрос 
      iec104ReciveArray[0]=iec104ReciveArray[0];
      iec104ReciveArray[1]=14;//длина  APDU=APCI(4)+ ASDU(10)
      iec104ReciveArray[2]=lowByte(txcnt);
      iec104ReciveArray[3]=highByte(txcnt);
      iec104ReciveArray[4]=lowByte(rxcnt);
      iec104ReciveArray[5]=highByte(rxcnt);
      iec104ReciveArray[6]=1;//type 1
      iec104ReciveArray[7]=01;//sq
      iec104ReciveArray[8]=20;//Inrogen
      iec104ReciveArray[9]=00;//AO
      iec104ReciveArray[10]=01;//Adress
      iec104ReciveArray[11]=00;//Adress
      iec104ReciveArray[12]=iecData[0];//IOA
      iec104ReciveArray[13]=iecData[1];//IOA
      iec104ReciveArray[14]=0;//IOA
      iec104ReciveArray[15]=iecData[2];//value [DATA 1]
      MessageLength = iec104ReciveArray[1]+2;
      client.write(iec104ReciveArray, MessageLength); 
      txcnt=txcnt+2;
      iec104ReciveArray[0]=iec104ReciveArray[0];
      iec104ReciveArray[1]=14;
      iec104ReciveArray[2]=lowByte(txcnt);
      iec104ReciveArray[3]=highByte(txcnt);
      iec104ReciveArray[4]=lowByte(rxcnt);
      iec104ReciveArray[5]=highByte(rxcnt);
      iec104ReciveArray[6]=1;
      iec104ReciveArray[7]=01;
      iec104ReciveArray[8]=20;
      iec104ReciveArray[9]=00;
      iec104ReciveArray[10]=01;
      iec104ReciveArray[11]=00;
      iec104ReciveArray[12]=iecData[3];
      iec104ReciveArray[13]=iecData[4];
      iec104ReciveArray[14]=0;
      iec104ReciveArray[15]=iecData[5];
      MessageLength = iec104ReciveArray[1]+2;
      client.write(iec104ReciveArray, MessageLength); 
      delay(5);
      txcnt=txcnt+2;
      iec104ReciveArray[0]=iec104ReciveArray[0];
      iec104ReciveArray[1]=22; 
      iec104ReciveArray[2]=lowByte(txcnt);
      iec104ReciveArray[3]=highByte(txcnt);
      iec104ReciveArray[4]=lowByte(rxcnt);
      iec104ReciveArray[5]=highByte(rxcnt);
      iec104ReciveArray[6]=11;//type 11
      iec104ReciveArray[7]=02;//sq
      iec104ReciveArray[8]=20;//cause
      iec104ReciveArray[9]=00;//AO
      iec104ReciveArray[10]=01;//Adress
      iec104ReciveArray[11]=00;//Adress
      iec104ReciveArray[12]=iecData[6];//IOA
      iec104ReciveArray[13]=iecData[7];//IOA
      iec104ReciveArray[14]=0;//IOA
      iec104ReciveArray[15]=iecData[8];//value [DATA 1]
      iec104ReciveArray[16]=iecData[9];//value [DATA 1] 
      iec104ReciveArray[17]=iecData[10];//QDS 
      iec104ReciveArray[18]=iecData[11];//IOA
      iec104ReciveArray[19]=iecData[12];//OA
      iec104ReciveArray[20]=0;//IOA
      iec104ReciveArray[21]=iecData[13];//value  [DATA 2]
      iec104ReciveArray[22]=iecData[14];//value  [DATA 2]
      iec104ReciveArray[23]=iecData[15];//IOA QDS 
      MessageLength = iec104ReciveArray[1]+2;
      client.write(iec104ReciveArray, MessageLength);
      delay(5);
      txcnt=txcnt+2;
      iec104ReciveArray[0]=iec104ReciveArray[0];
      iec104ReciveArray[1]=26; 
      iec104ReciveArray[2]=lowByte(txcnt);
      iec104ReciveArray[3]=highByte(txcnt);
      iec104ReciveArray[4]=lowByte(rxcnt);
      iec104ReciveArray[5]=highByte(rxcnt);
      iec104ReciveArray[6]=13;//type 13
      iec104ReciveArray[7]=02;//sq
      iec104ReciveArray[8]=20;//cause
      iec104ReciveArray[9]=00;//AO
      iec104ReciveArray[10]=01;//Adress
      iec104ReciveArray[11]=00;//Adress
      iec104ReciveArray[12]=iecData[16];//IOA
      iec104ReciveArray[13]=iecData[17];//IOA
      iec104ReciveArray[14]=0;
      iec104ReciveArray[15]=iecData[18];//value [DATA 1]
      iec104ReciveArray[16]=iecData[19];//value [DATA 1]
      iec104ReciveArray[17]=iecData[20];//value [DATA 1]
      iec104ReciveArray[18]=iecData[21];//value [DATA 1]
      iec104ReciveArray[19]=iecData[22];//IOA QDS
      iec104ReciveArray[20]=iecData[23];//IOA
      iec104ReciveArray[21]=iecData[24];//IOA
      iec104ReciveArray[22]=0;//IOA
      iec104ReciveArray[23]=iecData[25];//value [DATA 2]
      iec104ReciveArray[24]=iecData[26];//value [DATA 2]
      iec104ReciveArray[25]=iecData[27];//value [DATA 2]
      iec104ReciveArray[26]=iecData[28];//value [DATA 2]
      iec104ReciveArray[27]=iecData[29];//IOA QDS 
      MessageLength = iec104ReciveArray[1]+2;
      client.write(iec104ReciveArray, MessageLength);
      txcnt=txcnt+2;
    //Завершение общего опроса
      iec104ReciveArray[0]=iec104ReciveArray[0];
      iec104ReciveArray[1]=iec104ReciveArray[1];
      iec104ReciveArray[2]=lowByte(txcnt);
      iec104ReciveArray[3]=highByte(txcnt);
      iec104ReciveArray[4]=lowByte(rxcnt);
      iec104ReciveArray[5]=highByte(rxcnt);
      iec104ReciveArray[6]=100;//type
      iec104ReciveArray[7]=01;//sq
      iec104ReciveArray[8]=10;//cause AckTerm
      iec104ReciveArray[9]=00;
      iec104ReciveArray[10]=01;
      iec104ReciveArray[11]=00;
      iec104ReciveArray[12]=00;
      iec104ReciveArray[13]=00;
      iec104ReciveArray[14]=00;
      iec104ReciveArray[15]=20;
      MessageLength = iec104ReciveArray[1]+2;
      client.write(iec104ReciveArray, MessageLength);
      iec104ReciveArray[6]=00;//сброс для нормальног определения нового входящего пакета
    break;
   //APDU S
    case 01:
      txcnt=word(iec104ReciveArray[5],iec104ReciveArray[4]);
      iec104ReciveArray[0]=iec104ReciveArray[0];
      iec104ReciveArray[1]=14;
      iec104ReciveArray[2]=lowByte(txcnt);
      iec104ReciveArray[3]=highByte(txcnt);
      iec104ReciveArray[4]=lowByte(rxcnt);
      iec104ReciveArray[5]=highByte(rxcnt);
      iec104ReciveArray[6]=1;//type 1
      iec104ReciveArray[7]=01;//sq
      iec104ReciveArray[8]=01;//cause Cycl
      iec104ReciveArray[9]=00;//AO
      iec104ReciveArray[10]=01;//Adress
      iec104ReciveArray[11]=00;//Adress
      iec104ReciveArray[12]=iecData[0];//IOA
      iec104ReciveArray[13]=iecData[1];//IOA
      iec104ReciveArray[14]=0;//IOA
      iec104ReciveArray[15]=iecData[2];//value [DATA 1]
      MessageLength = iec104ReciveArray[1]+2;
      client.write(iec104ReciveArray, MessageLength); 
      delay(5);
      txcnt=txcnt+2;
      iec104ReciveArray[0]=iec104ReciveArray[0];
      iec104ReciveArray[1]=14;
      iec104ReciveArray[2]=lowByte(txcnt);
      iec104ReciveArray[3]=highByte(txcnt);
      iec104ReciveArray[4]=lowByte(rxcnt);
      iec104ReciveArray[5]=highByte(rxcnt);
      iec104ReciveArray[6]=1;//type 1 Bool
      iec104ReciveArray[7]=01;//sq
      iec104ReciveArray[8]=01;//cause Cycl
      iec104ReciveArray[9]=00;//AO
      iec104ReciveArray[10]=01;//Adress
      iec104ReciveArray[11]=00;//Adress
      iec104ReciveArray[12]=iecData[3];//IOA
      iec104ReciveArray[13]=iecData[4];//IOA
      iec104ReciveArray[14]=0;//IOA
      iec104ReciveArray[15]=iecData[5];//value [DATA 1]
      MessageLength = iec104ReciveArray[1]+2;
      client.write(iec104ReciveArray, MessageLength); 
      delay(5);
      txcnt=txcnt+2;
      iec104ReciveArray[0]=iec104ReciveArray[0];
      iec104ReciveArray[1]=22; 
      iec104ReciveArray[2]=lowByte(txcnt);
      iec104ReciveArray[3]=highByte(txcnt);
      iec104ReciveArray[4]=lowByte(rxcnt);
      iec104ReciveArray[5]=highByte(rxcnt);
      iec104ReciveArray[6]=11;//type 11 Int
      iec104ReciveArray[7]=02;//sq
      iec104ReciveArray[8]=01;//cause Cycl
      iec104ReciveArray[9]=00;//AO
      iec104ReciveArray[10]=01;//Adress
      iec104ReciveArray[11]=00;//Adress
      iec104ReciveArray[12]=iecData[6];//IOA
      iec104ReciveArray[13]=iecData[7];//IOA
      iec104ReciveArray[14]=0;//IOA
      iec104ReciveArray[15]=iecData[8];//value  [DATA 1]
      iec104ReciveArray[16]=iecData[9];//value  [DATA 1]
      iec104ReciveArray[17]=iecData[10];//QDS 
      iec104ReciveArray[18]=iecData[11];//IOA
      iec104ReciveArray[19]=iecData[12];//OA
      iec104ReciveArray[20]=0;//IOA
      iec104ReciveArray[21]=iecData[13];//value  [DATA 2]
      iec104ReciveArray[22]=iecData[14];//value  [DATA 2]
      iec104ReciveArray[23]=iecData[15];//IOA QDS 
      MessageLength = iec104ReciveArray[1]+2;
      client.write(iec104ReciveArray, MessageLength);
      delay(5);
      txcnt=txcnt+2;
      iec104ReciveArray[0]=iec104ReciveArray[0];
      iec104ReciveArray[1]=26;
      iec104ReciveArray[2]=lowByte(txcnt);
      iec104ReciveArray[3]=highByte(txcnt);
      iec104ReciveArray[4]=lowByte(rxcnt);
      iec104ReciveArray[5]=highByte(rxcnt);
      iec104ReciveArray[6]=13;//type 13 Float
      iec104ReciveArray[7]=02;//sq
      iec104ReciveArray[8]=01;//cause Cycl
      iec104ReciveArray[9]=00;//AO
      iec104ReciveArray[10]=01;//Adress
      iec104ReciveArray[11]=00;//Adress
      iec104ReciveArray[12]=iecData[16];//IOA
      iec104ReciveArray[13]=iecData[17];//IOA
      iec104ReciveArray[14]=0;
      iec104ReciveArray[15]=iecData[18];//value [DATA 1]
      iec104ReciveArray[16]=iecData[19];//value  [DATA 1]
      iec104ReciveArray[17]=iecData[20];//value [DATA 1]
      iec104ReciveArray[18]=iecData[21];//value  [DATA 1]
      iec104ReciveArray[19]=iecData[22];//IOA QDS
      iec104ReciveArray[20]=iecData[23];//IOA
      iec104ReciveArray[21]=iecData[24];//IOA
      iec104ReciveArray[22]=0;//IOA
      iec104ReciveArray[23]=iecData[25];//value [DATA 2]
      iec104ReciveArray[24]=iecData[26];//value [DATA 2]
      iec104ReciveArray[25]=iecData[27];//value [DATA 2]
      iec104ReciveArray[26]=iecData[28];//value [DATA 2]
      iec104ReciveArray[27]=iecData[29];//IOA QDS 
      MessageLength = iec104ReciveArray[1]+2;
      client.write(iec104ReciveArray, MessageLength);
      txcnt=txcnt;
    break;
    case 67:
    //TESTFR 
      iec104ReciveArray[0]=iec104ReciveArray[0];
      iec104ReciveArray[1]=iec104ReciveArray[1];
      iec104ReciveArray[2] =131; //TESTFR con
      iec104ReciveArray[3] =0;
      iec104ReciveArray[4] =0;
      iec104ReciveArray[5] =0;
      MessageLength = iec104ReciveArray[1]+2;
      delay(10);
      client.write(iec104ReciveArray, MessageLength);
      iec104ReciveArray[0]=iec104ReciveArray[0];
      iec104ReciveArray[1]=26;//длина  APDU
      iec104ReciveArray[2]=lowByte(txcnt);
      iec104ReciveArray[3]=highByte(txcnt);
      iec104ReciveArray[4]=lowByte(rxcnt);
      iec104ReciveArray[5]=highByte(rxcnt);
      iec104ReciveArray[6]=13;//type 13
      iec104ReciveArray[7]=02;//sq
      iec104ReciveArray[8]=03;//spont
      iec104ReciveArray[9]=00;//AO
      iec104ReciveArray[10]=01;//Adress
      iec104ReciveArray[11]=00;//Adress
      iec104ReciveArray[12]=iecData[16];//IOA
      iec104ReciveArray[13]=iecData[17];//IOA
      iec104ReciveArray[14]=0;
      iec104ReciveArray[15]=iecData[18];//value [DATA 1]
      iec104ReciveArray[16]=iecData[19];//value  [DATA 1]
      iec104ReciveArray[17]=iecData[20];//value [DATA 1]
      iec104ReciveArray[18]=iecData[21];//value  [DATA 1]
      iec104ReciveArray[19]=iecData[22];//IOA QDS
      iec104ReciveArray[20]=iecData[23];//IOA
      iec104ReciveArray[21]=iecData[24];//IOA
      iec104ReciveArray[22]=0;//IOA
      iec104ReciveArray[23]=iecData[25];
      iec104ReciveArray[24]=iecData[26];
      iec104ReciveArray[25]=iecData[27];
      iec104ReciveArray[26]=iecData[28];
      iec104ReciveArray[27]=iecData[29];//IOA QDS 
      MessageLength = iec104ReciveArray[1]+2;
      client.write(iec104ReciveArray, MessageLength);
     break;
  }
  }
 }


Nach dem Laden der Skizze in Wireshark stellen wir fest, dass die Datenübertragung endlich begonnen hat.

Das Folgende ist eine Beschreibung der Struktur der ASDU <100> M_SP_NA_1-Singleton-Anzeige.



TypeId - Art der Information.
SQ - Klassifikator der Variablenstruktur.

Es sind zwei Datenblockstrukturen vorgesehen:

1. Ein Block, der i Informationsobjekte enthält, von denen jedes ein Informationselement (oder eine Kombination von Elementen) enthält; das höchstwertige Bit des Klassifikators der Variablenstruktur SQ (single / sequence) ist 0, die restlichen 7 Bits geben die Zahl i an.

2. Ein Block, der ein Informationsobjekt enthält, das j Elemente oder die gleichen Kombinationen von Informationselementen enthält; Das höchstwertige Bit (27 = 80h) des SQ-Qualifiers ist 1, die restlichen 7 Bits geben die Zahl j an.

Bild


CauseTx - der Grund für die Übertragung.

Bild


Adr - Die Adresse des Slaves (angegeben bei der Konfiguration des Assistenten).
IOA - Adresse des Informationsobjekts, an diese Adresse bringt die steuernde Station ihren Tag
SIQ an - ein Indikator für die Qualität des übertragenen Signals.

Die ASDU-Struktur des Funktionsbausteins <11> M_ME_NB_1 :

Wireshark


In Reaktion auf die empfangenen Daten sendet der Master Blöcke im S-Format und der Prozess wird so lange wiederholt, bis das überwachte (Slave-) Gerät keine Rahmen mehr überträgt.

5. Testverfahren


Mit Testverfahren wird der Zustand von Transportverbindungen überwacht. Der Vorgang wird unabhängig von der "Aktivität" der IP-Verbindung durchgeführt, wenn während der Steuerzeit t3 keine Frames (I, U, S) empfangen wurden. Der Zeitpunkt t3 ist genehmigungspflichtig und wird als "Timeout für das Senden von Testblöcken bei langen Ausfallzeiten" bezeichnet. Das Testverfahren wird durch Senden einer Test-APDU (TESTFR = act) implementiert, die von der empfangenen Station mit Hilfe der APDU (TESTFR = con) bestätigt wird.

Bild


Wireshark


Wenn eine APDU von der steuernden (Master-) Station ankommt, deren Wert im Byte des APDU-Typs 60 Netze (TESTFR) entspricht, zeigt dies an, dass zum Zeitpunkt t3 (I, U, S) keine Frames von der gesteuerten Station empfangen wurden. Wenn Sie während der Zeit t1 nicht mit einer Bestätigung antworten, wird die Verbindung getrennt.

Skizze
case 67:
      iec104ReciveArray[0]=iec104ReciveArray[0];//кадр переменной длины, начинающийся байтом START2 = 68h;
      iec104ReciveArray[1]=iec104ReciveArray[1];//длина APDU LENGHT
      iec104ReciveArray[2] = 131; //TESTDT con
      iec104ReciveArray[3] =0;
      iec104ReciveArray[4] =0;
      iec104ReciveArray[5] =0;
      MessageLength = iec104ReciveArray[1]+2;//определение длины сообщения + 2 байта Start68H and Lenght
      delay(10);
      client.write(iec104ReciveArray, MessageLength);


Wireshark


Das ist alles, wenn jemand interessiert ist, dann werde ich im nächsten Artikel das IEC 670-5-104-Protokoll von der Master-Station am Beispiel des Arduino betrachten.

Jetzt auch beliebt: