FUNCTION "DatenInSort" : Void
TITLE = Datensort-Modul
{ S7_Optimized_Access := 'FALSE' }
AUTHOR : IBAE
FAMILY : DLISTE
NAME : DatenIn
VERSION : 0.1
//COPYRIGHT by Ingenieurbüro A.Emmert
//Ortsstr.33, D-869925 Fuchstal (Germany)
//Tel.: 0049(0)8243-1254
//Version: ILS2100 / 06.11.2009
//
//Datenblock in Datenliste einsortieren (aufsteigend)
//SSDB:    Datenlisten-DB
//SSDW:    Datenlisten-1.DW
//INDATEN: Pointer, wo einzutragende Daten stehen (P#DB1.DBX0.0, P#M220.0) 
//RE_VAL:  Rückmeldungen:
//   Bit0: Kein Datenlistenbereich / falscher Kopfinhalt / Endekennung
//   Bit1: SFC20-Aufruf mit Fehler
//   Bit2: Liste ist voll
//   Bit3: Frei
//   Bit4: Undefinierte Indaten
//   Bit5: Gespeicherte Daten <= 0 (Inhalt ungültig)
//   Bit6: Frei
//   Bit7: Eintrag ist richtig erfolgt
//
   VAR_INPUT 
      SSDB : Int;   // Datenlisten-DB
      SSDW : Int;   // Datenlisten-1.DW
      INDATEN : Pointer;   // InDaten-Schnittstelle
   END_VAR

   VAR_OUTPUT 
      RE_VAL : Byte;   // Rückmeldung
   END_VAR

   VAR_TEMP 
      Quelle : Any;   // Zeiger, wo Rein-Daten sind
      Ziel : Any;   // Zeiger, FIFO-Stelle
      Kopf : Byte;   // Datenliste-Kennnung (DA)
      Datensatzlaenge : Byte;   // Datensatzlänge in Word (01 - F0) F0=128
      Listenlaenge : Int;   // Länge der Datenliste (maximale Anzahl der Datensätze)
      Stammdaten : Int;   // Stammdatenlänge in Word (1 - 9)
      Belegt06 : Int;   // reserviert von Datenliste
      Belegt08 : Int;   // reserviert von Datenliste
      Belegt10 : Int;   // reserviert von Datenliste
      Belegt12 : Int;   // reserviert von Datenliste
      AnzahlEintraege : Int;   // Anzahl der eingetragenen Datensätze
      Reserve16 : Int;   // Reserve
      Reserve18 : Int;   // Reserve
      DBDatenliste : Word;   // Datenlisten-DB
      SFC_RET_VAL : Int;   // Rückmeldung SFC-Aufruf
      SFC_DB_LENGTH : Word;   // Rückmeldung SFC-Aufruf
      Datenlisten_Ende : Word;   // Ende der Datenliste
      AR2_Speicher : DWord;   // Adress-Register 2 zwischenspeichern
      Schleife : Word;   // Loopzähler
      DBInDaten : Word;   // Indaten-DB, falls angegeben
      InDaten_Pointer : DWord;   // In-Daten-Pointer: Kennung, Adresse
      InDaten_Startpunkt : Word;   // In-Daten-Startpunkt: Adresse
      Sort_Daten : DInt;   // Einzusortierende Daten (DWord)
      Datenblock_inBytes : Word;   // Datenblocklänge in Bytes
      SFC_WRITE_PROT : Bool;   // Rückmeldung SFC-Aufruf
      Lesestelle : Int;   // An dieser Stelle Datensatz lesen
      Min_Lesestelle : Int;   // Minimal sinnvolle Lesestelle
      Max_Lesestelle : Int;   // Maximal sinnvolle Lesestelle
      Savestelle : Int;   // An dieser Stelle wird In-Datensatz gespeichert
      Lese_Daten : DInt;   // In Tabelle gelesenen Daten
      Holstelle : Int;   // Freiraum schaffen: Stelle zum Daten holen
      Bringstelle : Int;   // Freiraum schaffen: Stelle zum Daten schreiben
      Holzeiger : DWord;   // Freiraum schaffen: Zeiger zum Daten holen
      Bringzeiger : DWord;   // Freiraum schaffen: Zeiger zum Daten schreiben
      AR1Zeiger : DWord;   // Statt AR1 (ging nur bis DB-Länge <= 8191 Bytes)
   END_VAR


BEGIN
NETWORK
TITLE = Schnittstellen-DB sinnvoll ?
      TAR2;
      T #AR2_Speicher;//AR2 zwischenspeichern

      L #SSDB;
      T #DBDatenliste;

//      CALL  TEST_DB
//         DB_NUMBER  :=#DBDatenliste
//         RET_VAL    :=#SFC_RET_VAL
//         DB_LENGTH  :=#SFC_DB_LENGTH
//         WRITE_PROT :=#SFC_WRITE_PROT

      CALL "TEST_DB_TO_ATTR_DB"
      (  DB_Number                   := #DBDatenliste , 
         RetVal                      := #SFC_RET_VAL , 
         DB_Length                   := #SFC_DB_LENGTH , 
         Write_Prot                  := #SFC_WRITE_PROT
      );

      L #SFC_RET_VAL;
      L 2#0000_0000_0000_0000;
      <>I;
      O #SFC_WRITE_PROT;
      SPB Err0;//kein Datenlisten-Bereich

NETWORK
TITLE = Datenlistekopf holen
//Quelle-Pointer erzeugen:
      L 16#1004;//Kennung 10 + Word=04
      T %LW0;//Any-Kennung, Datentyp
      L 16#000A;//10 Dw´s holen
      T %LW2;//Wiederholungen
      L #SSDB;
      T %LW4;//DB_Nummer
      L #SSDW;//Adresse
      SLD 3;
      L 16#8400_0000;//Kennung: Daten
      OD;
      T %LD6;//Kennung, Adresse

      CALL BLKMOV//1.-10.DW Datenliste holen
      {blk_type := 'Variant'}
      (  SRCBLK                      := #Quelle , 
         RET_VAL                     := #SFC_RET_VAL , 
         DSTBLK                      := P#L20.0 WORD 10
      );

      L #SFC_RET_VAL;
      L 2#0000_0000_0000_0000;
      <>I;
      SPB Err1;

NETWORK
TITLE = Zeigerüberprüfung
      L #Kopf;//Datenliste-Kopf
      L 16#DB;//= Datenlistekennung ?
      <>I;//Nein !
      SPB Err0;//kein Datenlistebereich

      L 1;
      L #Datensatzlaenge;//Datenblocklänge
      >I;
      SPB Err0;//kein Datenlistebereich

      L 128;
      >I;
      SPB Err0;//kein Datenlistebereich

      L 1;
      L #Listenlaenge;//Max.Anzahl von Datenblöcken
      >I;
      SPB Err0;//kein Datenlistebereich

      L 1;
      L #Stammdaten;//Anzahl der Stammdaten
      >I;
      SPB Err0;//kein Datenlistebereich

      L 9;
      >I;
      SPB Err0;//kein Datenlistebereich

      L #Stammdaten;//Anzahl der Stammdaten
      L #Datensatzlaenge;//Datenblocklänge
      >I;
      SPB Err0;//kein Datenlistebereich

      L #Listenlaenge;//Länge der Datenliste
      L #Datensatzlaenge;//Datenblocklänge
      *I;
      L 2;//DB byteorientiert
      *I;
      + 20;//Speichern ab 10.DW
      L #SSDW;
      +I;
      T #Datenlisten_Ende;
      ITD;
      SLD 3;
      T #AR1Zeiger;///Statt AR1 (ging nur bis DB-Länge <= 8191 Bytes)

      AUF DB[ #DBDatenliste];

      L #Datenlisten_Ende;
      L #SFC_DB_LENGTH;
      >I;//Datenlisten-DB ist zu kurz!
      SPB Err0;//kein Datenlisten-Bereich

      L DBW[ #AR1Zeiger];
      L 16#DBEE;//Datenliste-Endekennung ?
      <>I;//Nein !
      SPB Err0;//kein Datenlisten-Bereich

      L #Datensatzlaenge;//Datenblocklänge
      L 2;
      *I;
      T #Datenblock_inBytes;//Datenblocklänge in Bytes

      L #AnzahlEintraege;//Anzahl der eingetragenen Datensätze
      L #Listenlaenge;//Max.Anzahl von Datenblöcken
      >=I;//Nein !
      SPB Err2;//Datenliste ist voll

NETWORK
TITLE = Indaten definiert ?

//In-DATEN-Pointer übernehmen:
      L P##INDATEN;
      LAR2;

      L W[ AR2, P#0.0];
      T #DBInDaten;//Indaten-DB

      L #DBInDaten;//Indaten-DB
      L 0;//Angegeben ?
      ==I;//Nein 
      SPB W401;

//      CALL  TEST_DB
//         DB_NUMBER  :=#DBInDaten
//         RET_VAL    :=#SFC_RET_VAL
//         DB_LENGTH  :=#SFC_DB_LENGTH
//         WRITE_PROT :=#SFC_WRITE_PROT

      CALL "TEST_DB_TO_ATTR_DB"
      (  DB_Number                   := #DBInDaten , 
         RetVal                      := #SFC_RET_VAL , 
         DB_Length                   := #SFC_DB_LENGTH , 
         Write_Prot                  := #SFC_WRITE_PROT
      );


      L #SFC_RET_VAL;
      L 2#0000_0000_0000_0000;//Fehler vorhanden ?
      <>I;//Ja !
      SPB Err4;//Undefinierte Indaten

      L D[ AR2, P#2.0];//Kennung, Adresse
      L 16#00FF_FFFF;//Ohne Kennung
      UW;
      SRW 3;//Ohne Bit
      T #InDaten_Startpunkt;

      L #Datensatzlaenge;//Datenblocklänge
      L 2;//DB byteorientiert
      *I;
      L #InDaten_Startpunkt;
      +I;
      L #SFC_DB_LENGTH;
      >I;//Indaten-DB ist zu kurz
      SPB Err4;//Undefinierte Indaten

W401:      L D[ AR2, P#2.0];//Kennung, Adresse
      T #InDaten_Pointer;
      LAR2;

      L #DBInDaten;//Indaten-DB
      L 0;//Angegeben ?
      ==I;//Nein 
      SPB W402;

      AUF DB[ #DBInDaten];

W402:      L D[ AR2, P#0.0];//Indaten überprüfen
      T #Sort_Daten;//1.Indaten speichern

      L #Stammdaten;
L400:      T #Schleife;

      L #DBInDaten;//Indaten-DB
      L 0;//Angegeben ?
      ==I;//Nein 
      SPB W403;

      AUF DB[ #DBInDaten];

W403:      L W[ AR2, P#0.0];//Indaten überprüfen
      L 0;//Etwas angegeben ?
      <>I;//Ja !
      SPB Nw05;//Weiter

      +AR2 P#2.0;

      L #Schleife;
      LOOP L400;

      SPA Err4;//Undefinierte Indaten

Nw05:      NOP 0;

NETWORK
TITLE = Minimale + maximale Lesestelle am Anfang
      L 1;
      T #Min_Lesestelle;//Minimal sinnvolle Lesestelle

      L #AnzahlEintraege;//Anzahl der eingetragenen Datensätze
      T #Max_Lesestelle;//Maximal sinnvolle Lesestelle

//Sonderfall: noch kein Eintrag: 
      L 0;//Eintrag schon vorhanden ? 
      >I;//Ja !
      SPB en05;

      L 1;//An 1.Stelle speichern
      T #Savestelle;//Adresse

      SPA Save;

en05:      NOP 0;

NETWORK
TITLE = Aktuelle Lesestelle errechnen
New:      L #Max_Lesestelle;//Maximal sinnvolle Lesestelle
      + 1;
      L #Min_Lesestelle;//Minimal sinnvolle Lesestelle
      -I;
      L 2;
      /I;
      L #Min_Lesestelle;//Minimal sinnvolle Lesestelle
      +I;
      T #Lesestelle;//An dieser Stelle Datensatz lesen

NETWORK
TITLE = Daten an Lesestelle auslesen
      L #Lesestelle;//An dieser Stelle Datensatz lesen
      + -1;
      L #Datenblock_inBytes;//Datenblocklänge in Bytes
      *I;
      L #SSDW;
      +I;
      + 20;//Offset für 1.Daten
      ITD;
      SLD 3;
      T #AR1Zeiger;///Statt AR1 (ging nur bis DB-Länge <= 8191 Bytes)

      AUF DB[ #DBDatenliste];
      L DBD[ #AR1Zeiger];//Datenliste-Daten lesen
      T #Lese_Daten;//In Tabelle gelesenen Daten
      L 0;//Nichts gespeicher oder negativ ?
      <=D;//Ja !
      SPB Err5;

NETWORK
TITLE = Suche fertig ?
      L #Max_Lesestelle;//Maximal sinnvolle Lesestelle
      L #Min_Lesestelle;//Minimal sinnvolle Lesestelle
      -I;
      L 0;//Suche fertig ?
      <I;//Ja !
      SPB ok;

NETWORK
TITLE = Gelesene Daten auswerten
      L #Sort_Daten;//Einzusortierende Daten 
      L #Lese_Daten;//In Tabelle gelesenen Daten
      >D;//Sort > Tabelle
      SPB MinP;

      L #Sort_Daten;//Einzusortierende Daten 
      >D;//Tabelle > Sort
      SPB MaxM;

      L #Lesestelle;//An dieser Stelle Datensatz lesen
      T #Savestelle;//An dieser Stelle wird In-Datensatz gespeichert

      SPB Frei;//Freiplatz schaffen

MinP:      L #Lesestelle;//An dieser Stelle Datensatz lesen
      + 1;
      T #Min_Lesestelle;//Minimal sinnvolle Lesestelle

      L #Max_Lesestelle;//Maximal sinnvolle Lesestelle
      >I;//Suche ist fertig
      SPB ok;

      SPA New;

MaxM:      L #Lesestelle;//An dieser Stelle Datensatz lesen
      + -1;
      T #Max_Lesestelle;//Maximal sinnvolle Lesestelle

      L #Min_Lesestelle;//Minimal sinnvolle Lesestelle
      <I;//Suche ist fertig
      SPB ok;

      SPA New;

NETWORK
TITLE = Speicherstelle ermitteln
ok:      L #Sort_Daten;//Einzusortierende Daten 
      L #Lese_Daten;//In Tabelle gelesenen Daten
      >D;//Sort > Tabelle
      SPB Plus;

      L #Lesestelle;//An dieser Stelle Datensatz lesen
      T #Savestelle;//An dieser Stelle wird In-Datensatz gespeichert

      SPA Frei;//Freiplatz schaffen

Plus:      L #Lesestelle;//An dieser Stelle Datensatz lesen
      + 1;
      T #Savestelle;//An dieser Stelle wird In-Datensatz gespeichert

NETWORK
TITLE = Freiraum für Speicherung schaffen
Frei:      L #Savestelle;//An dieser Stelle wird In-Datensatz gespeichert
      T "MW240";
      L #AnzahlEintraege;//Anzahl der eingetragenen Datensätze
      >I;//Eintrag ans Ende !
      SPB Save;

      L #AnzahlEintraege;//Anzahl der eingetragenen Datensätze
      L #Datenblock_inBytes;//Datenblocklänge in Bytes
      *I;
      L #SSDW;
      +I;
      + 20;//Offset für 1.Daten
      + -2;//Letzte Daten letzter Eintrag
      T #Holstelle;//Freiraum schaffen: Stelle zum Daten holen

      L #Holstelle;//Freiraum schaffen: Stelle zum Daten holen
      L #Datenblock_inBytes;//Datenblocklänge in Bytes
      +I;
      T #Bringstelle;//Freiraum schaffen: Zeiger zum Daten schreiben

      L #AnzahlEintraege;//Anzahl der eingetragenen Datensätze
      L #Savestelle;//An dieser Stelle wird In-Datensatz gespeichert
      -I;
      + 1;
      L #Datenblock_inBytes;//Datenblocklänge in Bytes
      *I;
      L 2;//da DW-Zugriff (2Byte)
      /I;
L110:      T #Schleife;

      L #Holstelle;//Freiraum schaffen: Stelle zum Daten holen
      ITD;
      SLD 3;
      T #Holzeiger;//Freiraum schaffen: Zeiger zum Daten holen
      L #Bringstelle;//Freiraum schaffen: Zeiger zum Daten schreiben
      ITD;
      SLD 3;
      T #Bringzeiger;//Freiraum schaffen: Zeiger zum Daten schreiben

      AUF DB[ #DBDatenliste];

      L DBW[ #Holzeiger];//Datenliste-Daten lesen
      T DBW[ #Bringzeiger];//Datenliste-Daten verschieben

      L #Holstelle;
      + -2;//2 Byte wegen DW-Zugriff
      T #Holstelle;//Freiraum schaffen: Stelle zum Daten holen

      L #Bringstelle;
      + -2;//2 Byte wegen DW-Zugriff
      T #Bringstelle;//Freiraum schaffen: Zeiger zum Daten schreiben

      L #Schleife;
      LOOP L110;

NETWORK
TITLE = Daten in Datenliste schreiben

//Quelle-Pointer erzeugen:

Save:      L 16#1004;//Kennung 10 + Word=04
      T %LW0;
      T %LW10;//Any-Kennung, Datentyp
      L #Datensatzlaenge;//Datenwords speichern
      T %LW2;
      T %LW12;//Wiederholungen

//DATEN-Pointer übernehmen:
      L #DBInDaten;
      T %LW4;//DB_Nummer
      L #InDaten_Pointer;
      T %LD6;//Kennung, Adresse

//Ziel-Pointer erzeugen:
//Kennung + Datenbytes s.o.

      L #SSDB;
      T %LW14;//DB_Nummer
      L #Savestelle;//Adresse
      + -1;
      L #Datenblock_inBytes;//Datenblocklänge in Bytes
      *I;
      L #SSDW;
      +I;
      + 20;//Offset für 1.Daten
      SLD 3;
      L 16#8400_0000;//Kennung: Daten
      OD;
      T %LD16;//Kennung, Adresse

      CALL BLKMOV//Datenliste-Daten speichern
      {blk_type := 'Variant'}
      (  SRCBLK                      := #Quelle , 
         RET_VAL                     := #SFC_RET_VAL , 
         DSTBLK                      := #Ziel
      );

      L #SFC_RET_VAL;
      L 2#0000_0000_0000_0000;
      <>I;
      SPB Err1;

      L #SSDW;
      + 14;//Anzahl der Einträge
      ITD;
      SLD 3;
      T #AR1Zeiger;///Statt AR1 (ging nur bis DB-Länge <= 8191 Bytes)

      AUF DB[ #DBDatenliste];
      L DBW[ #AR1Zeiger];//Anzahl der Einträge
      + 1;//Einträge +1
      T DBW[ #AR1Zeiger];//Anzahl der Einträge

NETWORK
TITLE = Fehlerausgabe / RET_VAL
      SET;//VKE = 1 ohne Fehler !!!
      L 2#0000_0000_1000_0000;//Daten wurden gespeichert
      SPA Ok_Mig;
Err0:      L 2#0000_0000_0000_0001;//Kein Datenlistebereich
      SPA Err;
Err1:      L 2#0000_0000_0000_0010;//SFC20-Aufruf mit Fehler
      SPA Err;
Err2:      L 2#0000_0000_0000_0100;//Datenliste ist voll
      SPA Err;
Err4:      L 2#0000_0000_0001_0000;//Undefinierte Indaten
      SPA Err;
Err5:      L 2#0000_0000_0010_0000;//Gespeicherte Daten <= 0 (Inhalt ungültig)

Err:      CLR;//VKE = 0 bei Fehler !!!

Ok_Mig:      T #RE_VAL;
      SAVE;//VKE in BIE-Bit speichern  

      L #AR2_Speicher;//AR2 zurückspeichern
      LAR2;

END_FUNCTION

