# DotNetSiemensPLCToolBoxLibrary (LibNoDave) Zugriff auf Dual-Port RAM / FB15



## Hans54216 (5 Februar 2016)

Hallo zusammen,

ich suche eine Möglichkeit mit der "DotNetSiemensPLCToolBoxLibrary" (LibNoDave) auf den DualPort RAM zuzugreifen.

Die SPS macht dies per FB15, welcher vom FC21 aufgerufen wird.
Zudem kann per FB15 (anhand FB2, FB3) auf NC und Antriebsmaschinendaten zugegriffen werden.

Der FB15 ist jedoch in "C für S7" erstellt. Somit kann ich diesen nicht öffnen.

Hardware ist eine 840dsl: NCU730.3 PN mit CPU 317F-3 PN/DP


Mir stellt sich nun die Frage, wie ich auf diese Daten zugreifen kann.


```
//FC21
      U     #Enable
      SPBN  noFB
      =     #C_LEnable
      L     #Funct
      T     #C_LFunct
      L     #IVAR1
      T     #C_LIVAR1
      L     #IVAR2
      T     #C_LIVAR2
      L     #Funct
      T     #C_LFunct
      L     P##S7Var
      LAR1  
      L     B [AR1,P#1.0]
      T     #C_Ltype
      L     W [AR1,P#2.0]
      T     #C_LnumberElements
      L     W [AR1,P#4.0]
      T     #C_LsubArea
      L     D [AR1,P#6.0]
      T     #C_Lmc7Ptr


      L     21
      T     #C_LBlockNo
      L     15
      T     #BpBlockNo
      UC    FB [#BpBlockNo]


      L     #C_LBlockFB15Return
      L     B#16#0
      ==I   
      SPBNB end


      L     #C_LErrCode
      T     #ErrCode
      U     #C_LError
      =     #Error
      NOT   
      SAVE  
      BE    
noFB: L     B#16#0
      T     #ErrCode
      R     #Error
      SAVE  


end:  BE
```


----------



## Jochen Kühner (5 Februar 2016)

Ich verstehe nicht ganz was du machen willst? In der SPS auf Daten von diesem FC Zugreifen, oder den Baustein betrachten?


----------



## Hans54216 (5 Februar 2016)

Ich möchte auf den DualPort Ram, sowie Maschinendaten per C# zugreifen. Den FB15 habe ich nur erwähnt, um zu zeigen wie´s die SPS macht.


----------



## LowLevelMahn (5 Februar 2016)

Ich kann mir nicht vorstellen das du von außen über TCP/IP auf den DualPort-Ram kommst - warum nutzt du nicht AGLink- zu langsam?


----------



## Hans54216 (5 Februar 2016)

AGLink ist zum einen Lizenzpflichtig, anderseits geht AGLink doch auch über TCP/IP, oder?

Kennt sich einer alternativ mit der Cap-Schnittstelle aus? Das HMI kann ja auch auf alles zugreifen.


----------



## LowLevelMahn (5 Februar 2016)

> AGLink ist zum einen Lizenzpflichtig



yupp



> anderseits geht AGLink doch auch über TCP/IP, oder?


wie stellst du dir denn vor von außen auf die SL zu kommen?
die DotNetSiemensPLCToolBoxLibrary nutzt doch auch nur TCP/IP für die Verbindung auf die 840D SL S7 (NC geht damit nicht)

also was hoffst/denkst/vermutest du wie erreichen zu können?


----------



## Hans54216 (5 Februar 2016)

LowLevelMahn schrieb:


> wie stellst du dir denn vor von außen auf die SL zu kommen?
> die DotNetSiemensPLCToolBoxLibrary nutzt doch auch nur TCP/IP für die Verbindung auf die 840D SL S7 (NC geht damit nicht)



AGLink, sowie HMI Operate laufen ja auch auf dem Laptop und greifen per Ethernet auf alle Daten(NC, PLC, DP) zu.



LowLevelMahn schrieb:


> also was hoffst/denkst/vermutest du wie erreichen zu können?



Die SPS greift ja per FB15 auf die NC zu. Wenn ich nun mit LibNoDave auf die gleiche Schnittstelle zugreife und das Ergebnis abfange hab ich ja die gewünschte Funktion.


----------



## Jochen Kühner (5 Februar 2016)

Kann Aglink es denn?


----------



## Hans54216 (5 Februar 2016)

Da es mit der Siemens HMI (Cap-Schnittstelle ??) sowie AGLink, beides über Ethernet, geht, ist es definitiv möglich.


----------



## Hans54216 (5 Februar 2016)

Hab mit der AGLink demo schon einzelne NC- sowie Antriebsmaschinendaten geschreiben, sowie ausgelesen.


----------



## LowLevelMahn (5 Februar 2016)

> Hab mit der AGLink demo schon einzelne NC- sowie Antriebsmaschinendaten geschreiben, sowie ausgelesen.



und du willst einfach das gleiche mit DotNetSiemensPLCToolBoxLibrary, LibNoDave machen?

Problem: DotNetSiemensPLCToolBoxLibrary, LibNoDave implementieren NUR das S7 Protokoll - aber nicht das NCK-Protokoll

kann es sein das der FB15 das NCK-Protkoll spricht?


----------



## Hans54216 (5 Februar 2016)

LowLevelMahn schrieb:


> und du willst einfach das gleiche mit DotNetSiemensPLCToolBoxLibrary, LibNoDave machen?



Ich verwende im Moment erfolgreich die "DotNetSiemensPLCToolBoxLibrary", welche mir auch recht gut gefällt. Zusätzlich kann im Fehlerfall oder implementieren zusätzlicher Funktionen einfach im Projekt nachgesehen werden, da Open Source und frei zugänglich über Github.




LowLevelMahn schrieb:


> Problem: DotNetSiemensPLCToolBoxLibrary, LibNoDave implementieren NUR das S7 Protokoll - aber nicht das NCK-Protokoll
> 
> kann es sein das der FB15 das NCK-Protkoll spricht?



FB15 ist in "C für S7" erstellt. Ich weis nicht was dieser genau macht.


----------



## Boxy (5 Februar 2016)

Der FB15 handelt oder macht die Kommuniaktion/Verbindung zwischen PLC und NC ...

Evtl. solltest Dir halt einmal "Create MyHMI-3GL ..." anschauen, da ist es von Siemens beschrieben wie man auf die Schnitstelle zugreift.
Kostet aber auch wieder etwas, da Optionspacket für OEM ...


----------



## Jochen Kühner (5 Februar 2016)

Dafür ist definitiv nichts in meiner Bibliothek implementiert. Hab auch noch nie an einer NC gearbeitet, und keine zum Testen zur verfügung, daher kann Ich da auch nichts implementieren.


----------



## LowLevelMahn (5 Februar 2016)

> Ich verwende im Moment erfolgreich die "DotNetSiemensPLCToolBoxLibrary", welche mir auch recht gut gefällt. Zusätzlich kann im Fehlerfall oder implementieren zusätzlicher Funktionen einfach im Projekt nachgesehen werden, da Open Source und frei zugänglich über Github.





> Dafür ist definitiv nichts in meiner Bibliothek implementiert. Hab auch noch nie an einer NC gearbeitet, und keine zum Testen zur verfügung, daher kann Ich da auch nichts implementieren.



das spezifische NC-Protokoll (nicht das S7-Protokoll) ist nicht in DotNetSiemensPLCToolBoxLibrary und LibNodave implementiert - darum geht es nicht


----------



## Thomas_v2.1 (5 Februar 2016)

Wobei es jetzt nicht der große Aufwand ist, das bei libnodave hinzuzufügen. Das sind vielleicht 20-30 Zeilen Code.
Ich komme an sowas zum Testen aber auch nicht ran.


----------



## Hans54216 (5 Februar 2016)

Thomas_v2.1 schrieb:


> Wobei es jetzt nicht der große Aufwand ist, das bei libnodave hinzuzufügen. Das sind vielleicht 20-30 Zeilen Code.
> Ich komme an sowas zum Testen aber auch nicht ran.



Das testen ist kein Problem. Ich hab mehrere Maschinen, sowie nen Teststand zum ausprobieren.
Mein Problem ist, dass ich nicht weiß wo ich ansetzen muss.

Wenn ihr mir helft das in libnodave zu integrieren, kann ich das gerne testen.


----------



## Jochen Kühner (5 Februar 2016)

Ich würds auf jeden Fall auf in meine Lib integrieren, aber habe nichts zu dem protokoll, und auch so keine ahnung von den nc cpus


----------



## Thomas_v2.1 (5 Februar 2016)

Ohne das jetzt einmal durch einen Compiler geschickt zu haben, müsste dazu eine Funktion wie diese hinzugefügt werden:

```
void DECL2 daveAddNCKToReadRequest(PDU *p, int area, int unit, int column, int line, int module, int linecount) {
    uc pa[] = {
        0x12, 0x08, 0x82,   /* VarSpec, Length, SyntaxId */
        0x00,               /* Area/Unit: 3 Bits Area, 5 Bits unit */
        0x00, 0x00,         /* column */
        0x00, 0x00,         /* line */
        0x00,               /* module */
        0x01,               /* linecount */
    };
    pa[3] = ((area & 0x07) << 5) | (unit & 0x1f);
    pa[4] = column / 256;
    pa[5] = column & 0xff;
    pa[6] = line / 256;
    pa[7] = line & 0xff;
    pa[8] = module;
    pa[9] = linecount;

    p->param[1]++;
    memcpy(p->param+p->plen, pa, sizeof(pa));
    p->plen += sizeof(pa);

    ((PDUHeader2*)p->header)->plenHi = p->plen / 256;
    ((PDUHeader2*)p->header)->plenLo = p->plen % 256;

    p->data = p->param+p->plen;
    p->dlen = 0;
    if (daveDebug & daveDebugPDU) {
        daveDumpPDU(p);
    }
}
```


----------



## Jochen Kühner (6 Februar 2016)

Ich würd das am Montag mal in meinen LibNoDave Fork und meine Toolbox einbauen! 
@Hans, könntest du das dann mal testen? (Aber bitte nicht an einer Produktiv Maschine)


----------



## Jochen Kühner (6 Februar 2016)

Wie Adressiert man den So eine NCK Variable in der Siemens HMI? Würde das dann gerne in die PLCTag Objekte so einbauen, das es geht so eine Variable über einen String aufzubauen! z.b. kann Ich ja sowas machen: 
var aa=new PLCTag("P#M30.0 BYTES 10"), oder var bb=new PLCTag("DB30.DBw40"), wie könnte das bei NCK Variablen aussehen?


----------



## Peter Gedöns (6 Februar 2016)

Hans54216 schrieb:


> Hallo zusammen,
> 
> ich suche eine Möglichkeit mit der "DotNetSiemensPLCToolBoxLibrary" (LibNoDave) auf den DualPort RAM zuzugreifen.
> 
> ...


Ich kann ja verstehen das man mit LibNoDave auf die NC zugreifen will,

Aber ein Lesen/ Schreiben  des DualPort Ram was soll das ?.

es gibt wohl 2 Fälle 
Ich schreibe von de NC Daten in den DualPort Ram  -> also kann ich die Daten auch aus der NC Lesen kostet halt was solange man nicht mit LibNoDave zugreifen kann.
Ich schreibe von der PLC Daten in den DualPort Ram -> kann ich auch mit LibNoDave die PLC Daten Lesen 

also ist aus meiner Sicht ein befummeln des DualPort Ram Unsinn.

ein 3 Fall fällt mir noch ein.
Ich möchte wisse was CompileZyklen ins oder durch den Ersteller geschützte Zyklen ins DualPort Ram schreiben .


----------



## Hans54216 (8 Februar 2016)

Jochen Kühner schrieb:


> Wie Adressiert man den So eine NCK Variable in der Siemens HMI? Würde das dann gerne in die PLCTag Objekte so einbauen, das es geht so eine Variable über einen String aufzubauen! z.b. kann Ich ja sowas machen:
> var aa=new PLCTag("P#M30.0 BYTES 10"), oder var bb=new PLCTag("DB30.DBw40"), wie könnte das bei NCK Variablen aussehen?






Weiß aber nicht ob das so einfach geht. Je nach NC können die Bereiche unterschiedlich sein.
Für die PLC werden die Bereiche per NC-Var-Selector(Siemens Tool) ermittelt.


> V[5]    M      r0027                                       float   27    4     V5_M_r0027_27
> V[5]    M      r0035                                       float   35    4     V5_M_r0035_35



Beispiel für FB2 Adresse:


----------



## Hans54216 (8 Februar 2016)

Peter Gedöns schrieb:


> Ich kann ja verstehen das man mit LibNoDave auf die NC zugreifen will,
> 
> Aber ein Lesen/ Schreiben  des DualPort Ram was soll das ?.
> 
> ...




Oder du möchtest schnell einen Versuch durchführen ohne erst etwas lange in der PLC zu programmieren. Durch den DualPort Ram hast du ja bereits einen definierten, synchronaktion fähigen Bereich, der nicht vom Anwender verwendet wird. Im Gegensatz zu R-Parametern.


----------



## Hans54216 (10 Februar 2016)

Jochen Kühner schrieb:


> Ich würd das am Montag mal in meinen LibNoDave Fork und meine Toolbox einbauen!
> @Hans, könntest du das dann mal testen? (Aber bitte nicht an einer Produktiv Maschine)



Hallo Jochen,

hast du den Code bereits in deine LibNoDave eingebaut?


----------



## Jochen Kühner (11 Februar 2016)

Ja, habs heute Probiert...
compilert aber nicht...

Es gibt kein "PDUHeader2" und "PDUHeader" enthält plenHi und plenLow nicht!


----------



## Thomas_v2.1 (11 Februar 2016)

Jochen Kühner schrieb:


> Ja, habs heute Probiert...
> compilert aber nicht...
> 
> Es gibt kein "PDUHeader2" und "PDUHeader" enthält plenHi und plenLow nicht!



In libnodave aber schon (0.8.5.1).


----------



## Jochen Kühner (11 Februar 2016)

Danke...

Hab Ich irgendwie beim mergen der libnodave änderungen in meinen fork übersehen...


Habs mal eingebaut, gibt neue Tags vom Typ: "PLCNckTag" damit müsste man es mal versuchen! ie haben dann Felder "NckArea, NckUnit, ...". Wie groß ist den eine so gelesene Variable? Im Moment targe ich fix 1 Byte als große pro req. ein!


----------



## Hans54216 (11 Februar 2016)

Hans54216 schrieb:


> Für die PLC werden die Bereiche per NC-Var-Selector(Siemens Tool) ermittelt.
> 
> Beispiel für FB2 Adresse:
> Anhang anzeigen 31628





Jochen Kühner schrieb:


> Habs mal eingebaut, gibt neue Tags vom Typ: "PLCNckTag" damit müsste man es mal versuchen! ie haben dann Felder "NckArea, NckUnit, ...". Wie groß ist den eine so gelesene Variable? Im Moment targe ich fix 1 Byte als große pro req. ein!



Die Größe der Variable ist vom Datentyp abhängig. Im Bild für den FB2 Aufruf steht bei "laenge" die Länge des Datentyps. Da es sich hier um eine Real (Type 0x8) handelt ist die länge 4.


----------



## Jochen Kühner (11 Februar 2016)

Ok, Ich nehm die gleiche größe wire bei den anderen Tags.

So solltest du nun vlt einen Tag Definieren und lesen können:


```
[COLOR=blue]var[/COLOR] tag=[COLOR=blue]new[/COLOR] [COLOR=#2b91af]PLCNckTag[/COLOR]() { TagDataType = [COLOR=#2b91af]TagDataType[/COLOR].Float, NckArea = 0xa, NckUnit = 0x8,NckColumn = 0x23, NckLine = 0x1,NckModule = 0x1a,NckLinecount = 0x1};
```

kannst du das mal testen?


----------



## Jochen Kühner (12 Februar 2016)

Konntest/bzw kannst du es testen?


----------



## Hans54216 (12 Februar 2016)

Wollte es testen. Bekomme beim Kompelieren aber immer folgenden Fehler:

Der Typ- oder Namespacename 'DotNetSiemensPLCToolBoxLibrary' konnte nicht gefunden werden. (Fehlt eine Using-Direktive oder ein Assemblyverweis?)

Mit der alten .dll (v1.0.0) funktioniert es.


----------



## Jochen Kühner (12 Februar 2016)

??? woher holst du denn die DLL? nimmst du das Nuget Paket?


----------



## Hans54216 (12 Februar 2016)

Von:
https://github.com/dotnetprojects/DotNetSiemensPLCToolBoxLibrary


----------



## Jochen Kühner (12 Februar 2016)

Keine Ahnung... Ich kann alle Projekte in der Solution compilieren...


----------



## Jochen Kühner (12 Februar 2016)

Vlt nimmst mal das Nuget: https://www.nuget.org/packages/DotNetProjects.DotNetSiemensPLCToolBoxLibrary/


----------



## Hans54216 (12 Februar 2016)

Wie funktioniert NuGet? Hab den Befehl aus dem Link ausgeführt. Anschließend konnte ich dein Projekt nicht mehr compilieren


----------



## Jochen Kühner (12 Februar 2016)

könntest du mir deine solution vlt zukommen lassen?


nuget pakete kannst du mit rechtsklick im solutionexplorer auf das projekt verwalten!


----------



## Jochen Kühner (12 Februar 2016)

Hab dir mal ein Beispiel Prg gebastelt...


----------



## Hans54216 (12 Februar 2016)

Hab das Beispiel einmal gestartet und dabei beim "ReadValue(tag)" folgendes Exception bekommen.




Am Montag werde ich mir das ganze genauer anschauen.


----------



## Hans54216 (13 Februar 2016)

Hans54216 schrieb:


> Wollte es testen. Bekomme beim Kompelieren aber immer folgenden Fehler:
> 
> Der Typ- oder Namespacename 'DotNetSiemensPLCToolBoxLibrary' konnte nicht gefunden werden. (Fehlt eine Using-Direktive oder ein Assemblyverweis?)
> 
> Mit der alten .dll (v1.0.0) funktioniert es.



Hab das Problem gefunden. Du hast das Framework deines Projektes von v4.0 nach v4.52 geändert. Deshalb konnte ich zwar alles programmieren und auch die using hinzufügen, beim compilieren kam dann aber der Fehler.

Framework v4.52 ist zwar für x64 recht schön, wird jedoch von WinXP(Windows XP Embedded) nicht mehr unterstützt. Da ist bei v4.0 ende.
In der Industrie wird XP Embedded noch einige Jahre in Verwendung sein. Deshalb versuche ich solche Programme bis max. .Net4.0 zu programmieren.


----------



## Jochen Kühner (13 Februar 2016)

Die DLL nutzt nun wieder Net 4.0! Hatte nur an einer stelle ein "await" drin, das hab Ich durch Task.Result geändert...

Ja geht den die Kommuniaktion zur NC?


----------



## Hans54216 (15 Februar 2016)

Beim Lesen bekomme ich folgendes Exception


```
else if (res != 0 && res != 10)
                            throw new Exception("Error: " + _errorCodeConverter(res));

{"Error: context is not supported. Step7 says:Function not implemented or error in telgram."}
 
 bei DotNetSiemensPLCToolBoxLibrary.Communication.PLCConnection.ReadValues(IEnumerable`1 valueList, Boolean useReadOptimization) in c:\Users\1\Documents\GitHub\_DotNetSiemensPLCToolBoxLibrary\LibNoDaveConnectionLibrary\Communication\PLCConnection.cs:Zeile 2533.
```


----------



## Jochen Kühner (15 Februar 2016)

vlt. kann thomas da helfen! wie sieht dein aufruf aus? gibts vlt eine wireshark aufzeichnung?


----------



## Hans54216 (15 Februar 2016)

Aufruf ist grundsätzlich wie in deinem Beispiel.


```
private void test()
        {
            var config = new PLCConnectionConfiguration("Test",
                LibNodaveConnectionConfigurationType.ObjectSavedConfiguration) { CpuIP = "192.168.214.1" };

            //var connection = new PLCConnection(config);
            DotNetSiemensPLCToolBoxLibrary.Communication.PLCConnection _myConn = null;
            string IPAdress = string.Empty;
            try
            {
                if (_myConn != null)
                {
                    if (_myConn.Connected)
                        _myConn.Disconnect();
                    _myConn.Dispose();
                }

                _myConn = new DotNetSiemensPLCToolBoxLibrary.Communication.PLCConnection("ConnectionName");

                _myConn.Configuration.CpuIP = !string.IsNullOrEmpty(IPAdress) ? IPAdress : "192.168.214.1";
                _myConn.Connect();
            }
            catch (Exception ex)
            {
            }

            var tag = new PLCNckTag() { TagDataType = TagDataType.Float, NckArea = 0xa, NckUnit = 0x8, NckColumn = 0x23, NckLine = 0x1, NckModule = 0x1a, NckLinecount = 0x1 };
            //var tag = new PLCTag("M1.0");

            _myConn.ReadValue(tag);

            Console.WriteLine("Tag:" + tag.Value);

            Console.ReadLine();
        }
```

Hier das wireshark
Anhang anzeigen r35_HMI.rar

Anhang anzeigen r35_LibNoDave.rar


----------



## Thomas_v2.1 (15 Februar 2016)

Hast du bei Libnodave überhaupt vorher eine Verbindung aufgebaut, oder ist dies nur im logfile nicht vorhanden?

In deinem HMI Logfile liest du:
Area = 5
Unit = 2
Column = 31
Line = 1
Module = 0x82
linecount = 1

Per Libnodave:
Area = 2
Unit = 8
Column = 35
Line = 1
Module = 0x1a
linecount = 1

Eine Area 0xa welche du in deinem Funktionsaufruf übergibst ist überhaupt nicht möglich, da dafür nur 3 Bits zur Verfügung stehen. Das geht dementsprechend maximal von 0 bis 7.
Ich kenne mich mit dem Sinumerik Zeugs Null aus, ich sehe nur was über den Draht geht.


----------



## Jochen Kühner (15 Februar 2016)

Thomas_v2.1 schrieb:


> Ich kenne mich mit dem Sinumerik Zeugs Null aus, ich sehe nur was über den Draht geht.



Wie gesagt Ich auch nicht, habe nur den Code von Thomas in libnodave und meine Bibliothek eingebaut....


----------



## Thomas_v2.1 (15 Februar 2016)

An seiner Stelle würde ich darum auch zuerst mit den gleichen Werten testen, die er von seinem HMI erfolgreich gelesen hat.

Wenn er Area 0xa übergibt, fliegt das Bit 4 raus, darum ist auf dem Draht dann nur noch eine Area 2 zu sehen.

In der Bibliothek von Jochen darf bei diesen Bereichen nichts automatisch gepackt werden. Ein Mischbetrieb zwischen "normalem" Variablenzugriff und NCK Daten ist in einem Telegramm nicht möglich. Auch bei den NCK-Datenbereichen die gemeinsam in einem Telegramm gelesen werden dürfen scheint es diverse Einschränkungen zu geben.


----------



## Jochen Kühner (15 Februar 2016)

Thomas_v2.1 schrieb:


> An seiner Stelle würde ich darum auch zuerst mit den gleichen Werten testen, die er von seinem HMI erfolgreich gelesen hat.
> 
> Wenn er Area 0xa übergibt, fliegt das Bit 4 raus, darum ist auf dem Draht dann nur noch eine Area 2 zu sehen.
> 
> In der Bibliothek von Jochen darf bei diesen Bereichen nichts automatisch gepackt werden. Ein Mischbetrieb zwischen "normalem" Variablenzugriff und NCK Daten ist in einem Telegramm nicht möglich. Auch bei den NCK-Datenbereichen die gemeinsam in einem Telegramm gelesen werden dürfen scheint es diverse Einschränkungen zu geben.



Das muß Ich dann noch anpassen, das keine gemischten Zugriffe erfolgen können... Werd Ich aber erst tun wenns überhaupt läuft! Woher weißt du das nichts gemischt werden darf, hast du das schon probiert?


----------



## Thomas_v2.1 (15 Februar 2016)

Hier gibt es einen langen Thread in dem ich immer mal mitlegesen habe um mich zu informieren:

http://www.sps-forum.de/simatic/735...en-und-antriebsparameter-lesen-schreiben.html


----------



## Jochen Kühner (15 Februar 2016)

Danke!!!

Nochwas, haben den die Bytes in der Antwort eine andere Reihenfolge als die für Step7 Variablen?


----------



## Hans54216 (15 Februar 2016)

Hab mir mal die Aufzeichnung genau angeschaut und den Code angepasst.


```
var tag = new PLCNckTag() { TagDataType = TagDataType.Float, NckArea = 0x5, NckUnit = 0x1, NckColumn = 0x23, NckLine = 0x1, NckModule = 0x82, NckLinecount = 0x1 };
```

Im Wireshark ist nur die Anfrage aufgezeichnet.

Den einzigen Unterschied, den ich gerade in meinen zwei neuen Aufzeichnungen sehe ist die "Protocol Data Unit Reference"

Anhang anzeigen r35_LibNoDave2.rar

Anhang anzeigen r35_Work.rar


----------



## Thomas_v2.1 (15 Februar 2016)

Die PDU Ref dient der Zugehörigkeit von Anfrage zur Antwort. Üblicherweise wird die jedes Telegramm um z.B. 1 erhöht. Eine Null ist theoretisch erlaubt, aber unüblich. Die originale libnodave macht das glaube ich nicht.
Zeig doch mal die funktionierende Aufzeichnunge inklusive Verbindungsaufbau. Vielleicht benötigt man noch einen anderen TSAP beim Verbindungsaufbau, um sich so zu verbinden, dass auch NCK Daten gelesen werden können.


----------



## Hans54216 (15 Februar 2016)

Thomas_v2.1 schrieb:


> Hier gibt es einen langen Thread in dem ich immer mal mitlegesen habe um mich zu informieren:
> 
> http://www.sps-forum.de/simatic/735...en-und-antriebsparameter-lesen-schreiben.html



Der Thread kommt mir bekannt vor, hab ihn vor Jahren gestartet.


----------



## Hans54216 (15 Februar 2016)

Beide Aufzeichnungen nun mit Verbindungsaufbau.

Anhang anzeigen r35_Work_LibNoDave_mit_Verbindungsaufbau.rar


----------



## Thomas_v2.1 (15 Februar 2016)

In der Aufzeichnung enthält dein "Work"-Logfile aber ebenfalls einen Fehler.


----------



## Hans54216 (15 Februar 2016)

Ist mir auch gerade aufgefallen, bekomme jetzt für alle Anfragen einen Fehler gemeldet. Starte die Maschine gerade neu.


----------



## Thomas_v2.1 (15 Februar 2016)

Vielleicht kann die NCU nur eine Verbindung verarbeiten. Wenn du neben libnodave noch mit einem anderen HMI draufhängst, ist das vielleicht zu viel. In deinem "HMI" Logfiles laufen außerdem auch zwei Verbindungen, eine die Datenbausteine liest, und eine andere die NCU Daten liest. Das sieht man in der Wireshark-Aufzeichnungen nicht mehr so auf einen Blick, weil ich die TCP-Ports aus der Statuszeile rauswerfe. Da muss man schon in die Telegramme reinschauen, oder einen passenden Filter setzen.


----------



## Hans54216 (15 Februar 2016)

Der Fehler war die Auswahl des Slots.
Der richtige ist Slot Nr. 4

Bekomme mit LibNoDave nun dieses Exception
{"Error: PLC responds with an unknown data type"}

Anhang anzeigen r35_Work_mit_Verbindungsaufbau2.rar


----------



## Hans54216 (15 Februar 2016)

LibNoDave scheint jetzt auch die richtige Antwort zu bekommen, kann mit dieser aber wohl noch nichts anfangen.

Anhang anzeigen r35_LibNoDave3_mit_Verbindungsaufbau_Work.rar


----------



## Thomas_v2.1 (15 Februar 2016)

Das Lesen an sich funktioniert.
Aber in libnodave fehlt die Erkennung diverser möglicher Transportgrößen, in diesem Fall 0x07. Das hat bisher nicht gestört, weil libnodave die Anfragen immer so gestellt hat, dass eine bekannte Transportgröße zurückkommt.

Ich kopiere mal alle die mir bekannten Größen aus dem Wireshark plugin die in libnodave ergänzt werden müssten, denn zumindest "OCTET STRING" kommt bei manchen Daten einer NCK auch noch vor:

```
/**************************************************************************
 * Transport sizes in data
 */
#define S7COMM_DATA_TRANSPORT_SIZE_NULL     0
#define S7COMM_DATA_TRANSPORT_SIZE_BBIT     3           /* bit access, len is in bits */
#define S7COMM_DATA_TRANSPORT_SIZE_BBYTE    4           /* byte/word/dword access, len is in bits */
#define S7COMM_DATA_TRANSPORT_SIZE_BINT     5           /* integer access, len is in bits */
#define S7COMM_DATA_TRANSPORT_SIZE_BDINT    6           /* integer access, len is in bytes */
#define S7COMM_DATA_TRANSPORT_SIZE_BREAL    7           /* real access, len is in bytes */
#define S7COMM_DATA_TRANSPORT_SIZE_BSTR     9           /* octet string, len is in bytes */

static const value_string data_transportsizenames[] = {
    { S7COMM_DATA_TRANSPORT_SIZE_NULL,      "NULL" },
    { S7COMM_DATA_TRANSPORT_SIZE_BBIT,      "BIT" },
    { S7COMM_DATA_TRANSPORT_SIZE_BBYTE,     "BYTE/WORD/DWORD" },
    { S7COMM_DATA_TRANSPORT_SIZE_BINT,      "INTEGER" },
    { S7COMM_DATA_TRANSPORT_SIZE_BDINT,     "DINTEGER" },
    { S7COMM_DATA_TRANSPORT_SIZE_BREAL,     "REAL" },
    { S7COMM_DATA_TRANSPORT_SIZE_BSTR,      "OCTET STRING" },
    { 0,                                    NULL }
};
```


----------



## Thomas_v2.1 (15 Februar 2016)

Nur mal rein aus Interesse: Woher weißt du dass du Slot 4 verwenden musst? Ich habe ein Logfile von jemand anderen, da wird Slot 3 verwendet. Gibt es so etwas wie eine Hardwarekonfiguration in Step7, aus der ersichtlich ist auf welchem Slot die Baugruppe sitzt? Und lässt sich diese frei verschieben?


----------



## Hans54216 (15 Februar 2016)

> Thomas_v2.1Nur mal rein aus Interesse: Woher weißt du dass du Slot 4 verwenden musst?​



siehe Bild


----------



## Thomas_v2.1 (15 Februar 2016)

Ah, danke.
Der Rest muss Jochen dir einbauen. Oder kannst du bei dir auch die libnodave anpassen? D.h. eine Anpassung in der nodave.c


----------



## Hans54216 (15 Februar 2016)

Da lass ich erst mal lieber die Finger weg. Normales C ist nicht gerade mein Freund.
Mach jetzt sowieso Feierabend.

@Jochen: Kannst du das bitte in die libnodave einbauen?


----------



## Jochen Kühner (15 Februar 2016)

Morgen!

wie siehts mit den bytes aus? Muß ich die drehen?


----------



## Thomas_v2.1 (15 Februar 2016)

Meines Wissens nach ist bei der Bytereihenfolge kein Unterschied zwischen NCK und SPS-Daten.


----------



## Jochen Kühner (15 Februar 2016)

Nur die 6 hat in libnodave gefehlt...

https://github.com/dotnetprojects/D...mmit/5c22d9f0053eb25d1b01ffb7a2454f6ef6a39cfd


----------



## Jochen Kühner (15 Februar 2016)

Ok, es gab nochmals 2 prüfungen...  
https://github.com/dotnetprojects/D...mmit/f3980a84a651d7c7c4499550fc5ed90f000f163a


----------



## Thomas_v2.1 (15 Februar 2016)

Jochen Kühner schrieb:


> Nur die 6 hat in libnodave gefehlt...


Dann hätte er ja keine Exception bekommen dürfen, oder wann wird die geworfen?


----------



## Jochen Kühner (15 Februar 2016)

Er prüft später in "[COLOR=rgba(0, 0, 0, 0.298039)]_daveTestResultData" nochmals...[/COLOR]


----------



## Thomas_v2.1 (15 Februar 2016)

Irgendwie ist libnodave mittlerweile auch ziemlich verfrickelt. Wenn man da genau hinguckt, keine Überprüfungen ob die Längenangaben mit dem reservierten Speicher zusammenpassen usw.. Es funktioniert zwar, aber Stand der Technik ist der Code nicht wirklich.


----------



## Jochen Kühner (15 Februar 2016)

Ich wollte das ja schon lange full managed in meine library implementieren... aber dazu fehlt die zeit...
(Hauptsächlich ging mir's ja um die push Telegramme von der CPU!)

P.S. wie siehts den mit der TIA B&B Kommunikation aus? Hast du denn da jetzt schon einiges entschlüsselt?


----------



## Thomas_v2.1 (15 Februar 2016)

Ich würde da eher auf Snap7 setzen, das hat eine vernünftige Codequalität. Bei TIA hab ich schon lange nicht weitergemacht. Hauptsächlich muss jemand die Authentifizierung entschlüsseln, denn auch die neuen 1200er kommunizieren nur noch mit. Ich habe da zwar schonmal ein paar Sachen rumprobiert, aber mir fehlt da etwas die Erfahrung mit den diversen kryptografischen Funktionen, und wie man sowas angeht das zu knacken (möglichst beweisbar ohne Disassemblieren).
Außerdem schraubt Siemens gerne mal am Protokoll rum, da würde ich erstmal abwarten bis sich das stabilisiert hat. Denn auch ohne die Authentifizierung ist das ordentlich Arbeit.


----------



## Hans54216 (16 Februar 2016)

Hab gerade eine Erfolgreiche Antwort der "ReadValue()" Methode bekommen.

In der Methode ist noch ein Fehler.
Hab die beiden Zeilen mit *.Add(false) hinzugefügt.


```
PLCConnection.cs Zeile 2497

if (nckT != null)
{
        usedShortRequest.Add(false);
        tagWasSplitted.Add(false);
        myPDU.addNCKToReadRequest(nckT.NckArea, nckT.NckUnit, nckT.NckColumn, nckT.NckLine, nckT.NckModule, nckT.NckLinecount);
}
```


----------



## Jochen Kühner (16 Februar 2016)

Danke, ist gefixt!!!


----------



## Jochen Kühner (17 Februar 2016)

Ist das soweit nun nutzbar, oder muß ich danoch arbeit reinstecken? Gabs nicht irgendwelche beschränkungen mit anzahl der gleichzeitig lesbaren Tags je bereich?


----------



## Hans54216 (17 Februar 2016)

Da muss schon noch arbeit reingesteckt werden.

Hab gerade das rotieren der Bytes eingebaut, wenn es keine Variable aus dem Antrieb ist. 

Bei den Bereichen müssen mehrere Faktoren berücksichtigt werden. Bin noch am Testen.

Wenn ich genaueres weiß schreib ich dir oder mach nen pull request.


----------



## Hans54216 (18 Februar 2016)

Hallo Jochen,

Ich versuche gerade einen String von der NC zu lesen.

Wenn ich im PLCNckTag zusätzlich zum Typ String noch die "ArraySize = 20" mitgebe, kommt im Buffer der Text auch an.

Beim Umwandeln des Strings kommt es aber zu einem Exception:

{"Der Index und die Anzahl müssen sich auf eine Position im Puffer beziehen.\r\nParametername: bytes"}


----------



## Hans54216 (18 Februar 2016)

@Jochen
Hier die Infos zu den Beschränkungen:



st_rupp schrieb:


> Zu den Achsen: Ich habe herausgefunden, dass man über den Bereich FeedDrive sowohl aus Block M wie auch aus Block 0x82 die Antriebsdaten lesen kann.
> In diesen beiden Blöcken befinden sich die gleichen Daten, jedoch ist die Unit-zu-Achsen-Zuordnung unterschiedlich. Im Block M entspricht die Unit des Antriebs den Achs-MD (AreaAxis / BlockM), d.h. wenn bei den Achs-MD Unit 3 die Z-Achse ist, ist bei den Antriebs-MD (im Block M) Unit 3 der Antrieb der Z-Achse.
> Im Block 0x82 sind die Achsen wie ihr ja bereits geschrieben hattet nach der Topologie im Antriebsstrang sortiert.. wie genau habe ich noch nicht herausgefunden.
> Bislang hab ich auch keinen Weg gefunden das "automatisiert" auszulesen, sondern hab Werte gelesen und die dann manuell mit dem HMI verglichen um die Zuordnung rauszubekommen... Ich verwende für die Antriebe jetzt einfach BlockM, da ist es klar.
> ...


----------



## Jochen Kühner (18 Februar 2016)

Hans54216 schrieb:


> Hallo Jochen,
> 
> Ich versuche gerade einen String von der NC zu lesen.
> 
> ...




Versuchs mal mit "CharArray", String ist ein S7String mit 2 Bytes header!


----------



## Jochen Kühner (18 Februar 2016)

Hans54216 schrieb:


> @Jochen
> Hier die Infos zu den Beschränkungen:



Das hier:

_Soweit ich es verstanden habe sind die Limitierungen wie folgt:_


Die Bereiche FeedDrive und MainDrive dürfen jeweils immer nur einzeln, nicht in Kombination mit anderen Bereichen gelesen werden. Bei anderen Bereichen ist das egal
Das gleichzeitige Lesen von Variablen aus mehreren Units in einem Auftrag ist NIE erlaubt, egal aus welchem Bereich
In den Bereichen FeedDrive und MainDrive dürfen max. 19 Variablen auf einmal gelesen werden, egal welcher Datentyp
Die Endian-Verdrehung betrifft (glaube ich) alles in den Bereichen MainDrive und FeedDrive, nicht nur die 0x8Y Blöcke

sagt mir aber alles nichts! Ich weiß nicht was der Bereich "_FeedDrive" ist, ... Wie gesagt Ich kenn mich mit NC nicht aus!_


----------



## Jochen Kühner (18 Februar 2016)

Endianess? Sind die gelesen werte nun richtig wie Ich SIe ausgebe (in der Value Property), oder sind die Bytes vertauscht?


----------



## Hans54216 (18 Februar 2016)

Jochen Kühner schrieb:


> Endianess? Sind die gelesen werte nun richtig wie Ich SIe ausgebe (in der Value Property), oder sind die Bytes vertauscht?



Je nach Herkunft der Variable:
Aus dem Antrieb -> richtig
Aus der NC -> falsch

Hab aber bereits eine Lösung am Testen.

Mit den Bereichen kann ich dir morgen eine Übersetzung schreiben.


----------



## Jochen Kühner (18 Februar 2016)

also bei allen NckPlcTags! kann ich dir fixen


----------



## Hans54216 (19 Februar 2016)

> _Limitierungen für die "__PLCNckTag"__ sind wie folgt:_
> 
> 
> Die Bereiche FeedDrive und MainDrive dürfen jeweils immer nur einzeln, nicht in Kombination mit anderen Bereichen gelesen werden. Bei anderen Bereichen ist das egal


PLCNckTag.NckArea == 5 || PLCNckTag.NckArea == 6 -> dürfen nicht in Kombination mit anderen Bereichen gelesen werden



> Das gleichzeitige Lesen von Variablen aus mehreren Units in einem Auftrag ist NIE erlaubt, egal aus welchem Bereich


PLCNckTag.NckUnit -> alle NckUnit in einem Auftrag müssen gleich sein



> In den Bereichen FeedDrive und MainDrive dürfen max. 19 Variablen auf einmal gelesen werden, egal welcher Datentyp


PLCNckTag.NckArea == 5 || PLCNckTag.NckArea == 6 -> dürfen max. 19 Variablen auf einmal gelesen werden, egal welcher Datentyp (Wobei die HMI maximal 17 Variablen liest)



> Die Endian-Verdrehung betrifft (glaube ich) alles in den Bereichen MainDrive und FeedDrive, nicht nur die 0x8Y Blöcke


PLCNckTag.NckArea == 5 || PLCNckTag.NckArea == 6 -> Endian-Verdreht wie Sps, die anderen Bereiche sind x86 
(Dafür hab ich bereits eine mögliche Lösung eingebaut!)


----------



## Jochen Kühner (19 Februar 2016)

Werd das nächste Woche einbauen... Vlt. Strukturier Ich auch das PLC Tag Objekt noch ein bischen um, das ein NckPLCTag nicht 1000 unbenutzte Properties hat...


----------



## Hans54216 (28 Februar 2016)

Währ super, wenn du das einbauen könntest.


----------



## Hans54216 (15 März 2016)

-----------


----------



## Hans54216 (21 März 2016)

Weiß jemand wie ich die Funktion vom FB5 "GetGUD" in C# nachbilde?


Die Funktion liefert anhand des Bereichs (NC, Kanal) und dem GUD-Variablennamen die Adresse in der bekannten Struktur. (Intern wird wieder der FB15 (C_für_S7) aufgerufen)

An Hand dieser Struktur(Werte mit der PLC ermittelt) kann ich mit der PLCLib die Variable lesen.


Nun möchte ich dies gern ebenfalls in meinem Programm machen, ohne die PLC anzulangen.


----------



## Thomas_v2.1 (24 März 2016)

Werden die Daten übers Netzwerk übertragen? Wenn ja, dann einen Mitschnitt machen und hier einstellen.


----------



## Hans54216 (25 März 2016)

Thomas_v2.1 schrieb:


> Werden die Daten übers Netzwerk übertragen? Wenn ja, dann einen Mitschnitt machen und hier einstellen.


Leider nicht. PLC und NC sind bei der 840d ja im selben Gehause.


----------



## Thomas_v2.1 (26 März 2016)

Hans54216 schrieb:


> Leider nicht. PLC und NC sind bei der 840d ja im selben Gehause.


Du könntest mal in die aufgerufenen FBs hineinschauen, und dort prüfen ob dort zumindest im Ansatz Telegrammaufbauten wiederzufinden sind die womöglich auch übers Netzwerk funktionieren könnten.
Bzw. wenn der intern aufgerufene FB15 für die NCK-Kommunikation die wir hier gelöst haben verwendet wird, ist der Aufbau evtl. identisch, und es müssen nur entsprechende Werte für die Parameter eingetragen werden.


----------



## Hans54216 (29 März 2016)

Thomas_v2.1 schrieb:


> Du könntest mal in die aufgerufenen FBs hineinschauen, und dort prüfen ob dort zumindest im Ansatz Telegrammaufbauten wiederzufinden sind die womöglich auch übers Netzwerk funktionieren könnten.
> Bzw. wenn der intern aufgerufene FB15 für die NCK-Kommunikation die wir hier gelöst haben verwendet wird, ist der Aufbau evtl. identisch, und es müssen nur entsprechende Werte für die Parameter eingetragen werden.



Ich vermute mal, dass der Aufbau der selbe ist.

Die entscheidende Frage ist, wie bekommt man die Parameter.

Gibt es vielleicht ne SoftSPS Demo, die den FB15 unterstützt oder hat jemand ne SoftSPS und kann nen Mitschnitt der Kommunikation zur NC machen?

Aus dem FB5 definitiv nicht.

FB5 "GetGUD":

```
L     DINO
      T     #C_LInstanzDb
      TAR2  
      T     #AR2_rett
      SRD   3
      T     #C_LInstanzOff


      L     W#16#8005
      T     #C_LBlockNo
      L     15
      T     #BpBlockNo
      UC    FB [#BpBlockNo]


      L     #C_LBlockFB15Return
      L     B#16#0
      ==I   
      SPBNB end


      UN    #Error
      SAVE  


end:  LAR2  #AR2_rett
      BE
```


----------



## Hans54216 (5 April 2016)

*NC file transfer*

*@Thomas_v2.1*

Ich hab ein Wireshark des File up/download gemacht. Kannst du dir das mal anschauen und mir sagen wie das Protokoll auszusehen hat?

Beim Upload wird die Datei: "/_N_MPF_DIR/_N_TEILEPROG1_MPF" aus der NC gelesen.

Beim Download wir die Datei: "/_N_MPF_DIR/_N_TEILEPROG2_MPF" zur NC übertragen.


Anhang anzeigen NC_File_transfer.rar



PI-Dienst File Delete: Datei "/_N_MPF_DIR/_N_TEILEPROG2_MPF" aus NC löschen.

Anhang anzeigen NC_File_Delete.rar


----------



## Thomas_v2.1 (10 April 2016)

Also die Grundstruktur habe ich soweit denke ich mal. 

Evtl. muss ich aufgrund der Erkenntnisse mit deinen Logfiles einige Dinge im Wireshark-Dissector anpassen. Bei den üblichen SPS-Funktionen hatten nämlich bisher bestimmte Felder immer den gleichen Wert. Jetzt bei deinen Logfiles gibt es auch mal andere Werte zu sehen.

Der "Upload" scheint die gleichen Methoden zu verwenden, die auch beim SPS Programmieren verwendet werden. Im Datenteil sind das (mehr oder weniger) zwei ASCII-Strings, mit einer Längenangabe vorweg. Wobei das erste Byte bei einer SPS noch bedeutet, in wie viele Teile der String zu zerlegen ist, dann folgt auch noch ein Null-Byte. Dieses wird z.B. beim Befehl zum Einketten der vorher hochgeladenen Bausteine angewendet. Bei deinem NC Upload gibt es auch ein vorangestelltes Byte mit dem Wert 3, aber der restliche String ist dann nur der Dateipfad den du hier angegeben hast, und ggf. ein P01 vorangestellt, also max. 2 Teile.

Wie auch immer. Wenn du das in/mit libnodave komplett umgesetzt haben möchtest, musst du dich da schon selber reinfuchsen. Ohne direkten Zugriff auf eine NC, und dann noch über den Umweg über Jochen und seine Bibliothek sind wir andernfalls noch Jahre mit dem Pingpongspielen beschäftigt.

Ich selber habe auch nur insofern Interesse daran, dass ich das in Wireshark korrekt anzeigen kann.


----------



## Thomas_v2.1 (10 April 2016)

Der String beim Upload ließe sich doch als 3 Teile interpretieren:
1) P01
2) _N_MPF_DIR/_N_TEILEPROG1_MPF
3) _N_F_XFER

Wobei _N_F_XFER nach meiner bisherigen Intepretation der PI-Service ist, beim SPS-Programmieren gibt es z.B. _INSE zum Einketten von Bausteinen. Theoretisch sollte der Aufbau beim Upload zwischen SPS und NC Kommunikation identisch sein, evtl. lassen sich dann doch Teile von den schon in libnodave vorhandenen Programmierfunktionen weiterbenutzen.


----------



## Hans54216 (11 April 2016)

Thomas_v2.1 schrieb:


> Wie auch immer. Wenn du das in/mit libnodave komplett umgesetzt haben möchtest, musst du dich da schon selber reinfuchsen. Ohne direkten Zugriff auf eine NC, und dann noch über den Umweg über Jochen und seine Bibliothek sind wir andernfalls noch Jahre mit dem Pingpongspielen beschäftigt.



Danke schon mal!

Ein bisschen hab ich mich schon eingearbeitet. Hab in der libnodave sowie der Toolbox von Jochen auch das schreiben auf NC Variablen erfolgreich eingebaut.
Das reine programmieren und testen sollte kein Problem sein.
Die Schwierigkeit sehe ich vor allem im Protokoll. 

Wenn du, Jochen oder wer sonst möchte mich dabei unterstützt, sollte es in einem überschaubaren Zeitraum funktionieren.



			
				Thomas_v2.1 schrieb:
			
		

> Ich selber habe auch nur insofern Interesse daran, dass ich das in Wireshark korrekt anzeigen kann.



Um das korrekt anzeigen zu können benötigst du ja den Aufbau des Telegramms. Was mir wiederum hilft das Telegramm nachzubilden und zu befüllen.


----------



## Thomas_v2.1 (11 April 2016)

Wir können ja erstmal mit dem NC Upload anfangen, denn der Ablauf ist noch in Teilen mit dem identisch welche die SPS verwendet, außerdem bekomme ich dadurch evtl. auch noch eine etwas bessere Struktur in die SPS-Teile.

Bei der SPS gibt es nämlich auch PI-Dienste. Aus dem SPS-Programm heraus lässt sich aber nur der für Stop und für Start aufrufen, darum fehlt mit da etwas der Vergleich.
Wie aus diesem Thread ersichtlich:
http://www.sps-forum.de/simatic/587...nd-den-pi-dienst-_n_f_pror-oder-nur-pror.html

sind bei der NC noch weitere Funktionen möglich. Mir ist bisher unbekannt, wie die Parameter des Funktionsaufrufs auf dem Netzwerk übertragen werden. Laut den NC-Handbüchern existieren dabei nur zwei Typen von Parametern: INT oder STRING. 

In dem 1. Telegramm in deinem File Upload mit Function 0x28, wäre meine aktuelle Vermutung, dass die erste Längenangabe für die Länge der Argumente (gesamt) ist, und dann wie auch immer die einzelnen Argumente dort hintereinandergehängt werden. Als letztes kommt dann der PI-Dienst der aufgerufen werden soll als STRING.
Oder der Partner entscheidet anhand des angegebenen PI-Dienstnamens, wie die Argumente zu interpretieren sind. Das wäre unschön, denn dann muss ich vorab alle Argumente und Argumenttypen kennen.

Vielleicht kannst du noch von anderen PI-Dienstaufrufen mit diversen Parametern Mitschnitte machen, um hoffentlich damit herausfinden zu können wie die Argumente codiert werden. Dann lässt sich hoffentlich eine universelle Funktion schreiben, die einen PI-Dienstaufruf auf dem Netzwerk abschickt.


----------



## Jochen Kühner (16 April 2016)

Ich hab deinen commit auf github mal gemerged....

Komm aber grad nicht wirklich dazu da was zu machen! Helfen kann iCH DIR NATÜRLICH GERNE (SOFERN ES MIR MÖGLICH IST)


----------



## Peter Gedöns (16 April 2016)

Thomas_v2.1 schrieb:


> Bei der SPS gibt es nämlich auch PI-Dienste. Aus dem SPS-Programm heraus lässt sich aber nur der für Stop und für Start aufrufen, darum fehlt mit da etwas der Vergleich.
> Wie aus diesem Thread ersichtlich:
> http://www.sps-forum.de/simatic/587...nd-den-pi-dienst-_n_f_pror-oder-nur-pror.html



ich bin mir nicht sicher was du mit PI Dienst meinst Start /Stop ist mir so mal unbekannt 


Das sind PI Dienste die man aus der PLC nutzen kann
es gibt da noch weiter die sind aber nicht dokumentiert 


PI-Dienst 
ASUP (Seite 921) Interrupt zuordnen
CANCEL (Seite 921) Cancel durchführen
CONFIG (Seite 922) Umkonfiguration von gekennzeichneten Maschinendaten
DIGION (Seite 922) Digitalisieren ein
DIGIOF (Seite 922) Digitalisieren aus
FINDBL (Seite 923) Suchlauf aktivieren
LOGIN (Seite 923) Kennwort aktivieren
LOGOUT (Seite 924) Kennwort rücksetzen
NCRES (Seite 924) NC-RESET auslösen
SELECT (Seite 924) Programm zur Abarbeitung für einen Kanal anwählen
SETUDT (Seite 925) Setzt die aktuellen User Daten aktiv
SETUFR (Seite 925) Anwender Frame aktivieren
RETRAC (Seite 926) Freifahren des Werkzeugs in Werkzeugrichtung
CRCEDN (Seite 926) Werkzeugschneide anlegen unter Eingabe der T-Nummer
CREACE (Seite 927) Werkzeugschneide anlegen mit der nächst höheren/freien D-Nummer
CREATO (Seite 927) Anlegen eines Werkzeuges unter Vorgabe einer T-Nummer
DELECE (Seite 92 Löschen einer Werkzeugschneide
DELETO (Seite 92 Werkzeug löschen
MMCSEM (Seite 929) Semaphoren für verschiedene PI-Dienste
TMCRTO (Seite 930) Anlegen eines Werkzeugs unter Angabe eines Namens, einer Duplonummer
TMFDPL (Seite 931) Leerplatzsuche zum Beladen
TMFPBP (Seite 932) Leerplatzsuche
TMGETT (Seite 933) T-Nummer zum vorgegebenen Werkzeugnamen mit Duplonummer
TMMVTL (Seite 934) Magazinplatz zum Beladen bereitstellen, Werkzeug entladen
TMPOSM (Seite 935) Magazinplatz oder Werkzeug positionieren
TMPCIT (Seite 936) Inkrementwert für Stückzahlzähler setzen
TMRASS (Seite 937) Rücksetzen des Aktiv-Status
TRESMO (Seite 937) Rücksetzen der Überwachungswerte
TSEARC (Seite 93 Komplexes Suchen über Suchmasken
TMCRMT (Seite 941) Multitool erzeugen
TMDLMT (Seite 941) Multitool löschen
POSMT (Seite 942) Multitool positionieren
FDPLMT (Seite 943) Leerplatz innerhalb des Multitools suchen/prüfen


----------



## Hans54216 (19 April 2016)

Thomas_v2.1 schrieb:


> Vielleicht kannst du noch von anderen PI-Dienstaufrufen mit diversen Parametern Mitschnitte machen, um hoffentlich damit herausfinden zu können wie die Argumente codiert werden. Dann lässt sich hoffentlich eine universelle Funktion schreiben, die einen PI-Dienstaufruf auf dem Netzwerk abschickt.



Hab gerade Urlaub. Ab Montag versuch ich mal so viele als Möglich mitzuschneiden.




Jochen Kühner schrieb:


> Komm aber grad nicht wirklich dazu da was zu machen! Helfen kann iCH DIR NATÜRLICH GERNE (SOFERN ES MIR MÖGLICH IST)



Hast du schon mal nen PI-Dienstaufruf (z.B. Start / Stop) mit der libnodave durchgeführt?


----------



## Thomas_v2.1 (19 April 2016)

Ich weiß nicht genau ob das überhaupt einem PI-Dienstaufruf entspricht. Ein Warm- oder Kaltstartbefehl der bei einer SPS ausgeführt wird, ist vom Aufbau zumindest identisch (oder sehr ähnlich) zu den von dir gezeigten NC-Telegrammen. Was wohl PI-Dienstaufrufe sind, wenn ich das richtig verstehe.

Bei einer SPS kann ich aus dem SPS-Programm heraus, z.B. einen Kalt- oder Warmstart an einer anderen CPU ausführen. Der entsprechende Baustein hat dafür Parameter, bei einem Kaltstart wird 'C' als Zeichen übergeben. Das sieht dann so aus wie ein paar der hier gezeigten NC-Aufrufe. Ein Start-Befehl an einer SPS sieht anders aus, der hat überhaupt keine weiteren Parameter. Das erste Byte im Parameter-Teil (was ich Function genannt habe) unterscheidet sich auch bei Start und Stopp.
Bei libnodave werden zum SPS starten und stoppen nur 1:1 die Bytes die reingeschoben, funktioniert auch ohne dass man versteht was da überhaupt passiert.

Ich kenne mich mit dem NC-Zeugs überhaupt nicht aus, außer dass ich da mal in die ein oder andere Betriebsanleitung einen Blick geworfen habe. Wenn du da Logfiles erstellst, solltest du darum schon mitdokumentieren was du da überhaupt gemacht hast. Was auch interessant ist, sind Antworten auf fehlerhafte Anfragen oder so etwas in der Richtung. Dann sieht man evtl. auch mal die Bedeutung von Feldern die vorher z.B. immer Null waren.


----------



## Jochen Kühner (19 April 2016)

Hans54216 schrieb:


> Hast du schon mal nen PI-Dienstaufruf (z.B. Start / Stop) mit der libnodave durchgeführt?



d.h.? eine 300er CPU gestartet bzw gestoppt? Das hat auf jeden Fall schon funktioniert


----------



## Hans54216 (22 April 2016)

@Thomas_v2.1:
Hab mal ein paar PI-Dienste aufgezeichnet.

Anhang anzeigen WireShark_20160422.rar


----------



## Thomas_v2.1 (22 April 2016)

Das ist schonmal aufschlussreich. Ich habe auch noch eine Beschreibung diverser PI-Dienste in dem Sinumerik-Addon für WinCC flexible gefunden, u.a. sind dort auch die Parameter für PI-Dienste der SPS beschrieben, aber die Beispiele fehlen mir dabei. Oder gibt es noch eine bessere Beschreibung in einem anderen Handbuch?

So wie es aussieht, hat auf dem Netzwerk die Funktion 0x28 (die ich z.Zt in Wireshark als "PLC Control" anzeige) allgemein die Funktion PI_START. Dann kommt als erstes die Länge und der Parameter, und dann Länge und Name des PI-Dienstes der aufgerufen wird. Wie die Parameter zu interpretieren sind, ist dann abhängig von dem verwendeten PI-Dienst.

Wo und wie wird denn überhaupt diese Funktion PI_START(..) aufgerufen? Macht man das in einem Skript, und wenn ja, in welcher Programmiersprache?
Um ein Äquivalent für libnodave zu schreiben, müsste man dazu eine varargs Funktion erstellen, da Anzahl und Datentyp der Argumente ja nicht festgelegt ist. Ich weiß aber nicht ob sich varargs dann auch in .Net verwenden lassen. Die Alternative wäre dann, für jeden PI-Dienst eine eigene Funktion zu erstellen.


----------



## Jochen Kühner (22 April 2016)

http://stackoverflow.com/questions/...-signature-for-a-function-that-takes-var-args


----------



## Hans54216 (23 April 2016)

Ich hab noch was schönen gefunden.
DB_PI (DB16): Dieser enthält die Stuktur der PI-Dienste.

Anhang anzeigen DB16 - DB_PI.txt


----------



## Thomas_v2.1 (23 April 2016)

Ist die Frage inwiefern das mit dem was übers Netzwerk geht korreliert.
Beispiel LOGIN:

```
LOGIN : STRUCT
     PIName : STRING [10]  := '_N_LOGIN_';
     p01 : BYTE  := 16#3;    //Bereich / Einheit
     p02 : CHAR  := 0;
     p11 : BYTE  := 16#8;    //Passwort
     p12 : BYTE  := 16#19;    //String Kennung !!!
    END_STRUCT ;
```
Übers Netzwerk:

```
0x28: Funktion PI_START
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd: Unbekannt
0x0e: Länge des Parameterblocks gesamt = 14
{ // Parameterblock
  0x03: Länge Argument 1 
  0x30, 0x30, 0x31: ASCII-String "001" -> (Bereich/Einheit)?
  0x09: Länge Argument 2 (Passwort) = 9 Zeichen
  0x5f, 0x4e, 0x5f, 0x4c, 0x4f, 0x47, 0x49, 0x4e, 0x5f: Passwort als ASCII-String
}
```

Steht das "001" dort für (Bereich/Einheit)?


----------



## Hans54216 (23 April 2016)

Thomas_v2.1 schrieb:


> Steht das "001" dort für (Bereich/Einheit)?



(Bereich/Einheit) ist jedenfalls "1".

Anhang anzeigen 32538


----------



## Thomas_v2.1 (23 April 2016)

Dein letzter Anhang funktioniert nicht.

In der WinCC flexible Sinumerik Doku steht zu dem Feld immer:
"3-digit Addressidentification from RangeID and Index"
Dieser Parameter ist bei allen PI-Diensten mit _N_xxxx im Namen immer vorhanden.
Kann ich das von der Bezeichnung her so stehen lassen? Dann muss ich nicht für jeden Dienst eine eigene Bezeichnung verwenden.

Die Struktur der PI-Dienste habe ich denke ich mal soweit. 
Der Parameterblock muss immer auf eine gerade Anzahl an Bytes aufgefüllt werden.

Das letzte 0xfd in den bisher unbekannten 7 Bytes zu Beginn könnte auch die maximale Stringlänge bedeuten (253). Dann sind die Strings sozusagen als S7-Strings mit Kopf zu verstehen, aber die Max-Länge wird nur einmalig übermittelt. Ich habe dort aber noch nie einen anderen Wert als 0xfd gesehen.

Bei deinem Logfile von "NC_File_Open" gibt es laut Doku noch einen Parameter "Editor Window Name". Was hast du dort eingetragen, oder ist dieser Parameter optional?
Denn im Logfile ist die Längenangabe 0x00, dann folgt obwohl die Stringlänge Null ist noch ein Null-Byte für den String, und dann noch ein Nullbyte um auf eine gerade Anzahl an Bytes im Parameterblock zu kommen. Das muss eine libnodave Funktion dann später ebenfalls berücksichtigen, wie das handzuhaben ist.

In Wireshark bastel ich mir daraus jetzt einen Pseudo-Funktionsaufruf, z.B.:

```
_N_F_OPEN(P01, _N_MPF_DIR/_N_TEILEPROG2_MPF, )
```
bzw. eigentlich mit Anführungszeichen:

```
_N_F_OPEN("P01", "_N_MPF_DIR/_N_TEILEPROG2_MPF", "")
```

So in der Art könnte man dann auch die Funktionen gestalten.

Ist das für den NC-Bereich sinnvoll?


----------



## Thomas_v2.1 (23 April 2016)

Thomas_v2.1 schrieb:


> Der Parameterblock muss immer auf eine gerade Anzahl an Bytes aufgefüllt werden.



Korrektur:
Jeder String muss inklusive des Längenbytes eine gerade Anzahl besitzen, und wird ggf. mit einem Füllbyte aufgefüllt.
Dann passt das auch zusammen, wenn die Längenangabe Null ist.


----------



## Hans54216 (24 April 2016)

Thomas_v2.1 schrieb:


> Dein letzter Anhang funktioniert nicht.










Thomas_v2.1 schrieb:


> Bei deinem Logfile von "NC_File_Open" gibt es laut Doku noch einen Parameter "Editor Window Name". Was hast du dort eingetragen, oder ist dieser Parameter optional?
> Denn im Logfile ist die Längenangabe 0x00, dann folgt obwohl die Stringlänge Null ist noch ein Null-Byte für den String, und dann noch ein Nullbyte um auf eine gerade Anzahl an Bytes im Parameterblock zu kommen. Das muss eine libnodave Funktion dann später ebenfalls berücksichtigen, wie das handzuhaben ist.



In diesem wireshark ist der Editor Name ein Leerstring.
Wenn du den wireshark aus meinem Paket nimmst (Ordner "File open change close\NC_File_Open.pcapng"), da ist der Editor Name "txt1".


----------



## Thomas_v2.1 (24 April 2016)

Ich habe mal eine Testfunktion für die PI-Dienste geschrieben. Zumindest für die PI-Dienste der NC (also die mit _N_ beginnen) sollte das funktionieren. Denn bei den NC PI-Diensten sind alle Parameter identisch kodiert, d.h. immer als String mit Längenangabe vorweg. Zumindest ist das bei allen so, deren Dokumentation ich gefunden habe.

Die Funktion ist nur hingeschrieben und absolut ungetestet!

```
int DECL2 davePIstart_nc(daveConnection *dc, const char *piservice, const char *param[], int paramCount) {
    int res;
    int i;
    PDU p, p2;
    int paramlen;
    int len;
    int pos;
    uc pa[1024]; 

#ifdef DEBUG_CALLS
    LOG2("davePIstart_nc(dc:%p)\n", dc);
    FLUSH;
#endif
    /* Header */
    pa[0] = 0x28;   /* Function code for PI-Start*/
    pa[1] = 0x00;   /* unknown */
    pa[2] = 0x00;
    pa[3] = 0x00;
    pa[4] = 0x00;
    pa[5] = 0x00;
    pa[6] = 0x00;
    pa[7] = 0xfd;   /* max. string length */
    pa[8] = 0x00;   /* Parameterblock length */
    pa[9] = 0x00;   /* Parameterblock length */

    /* Parameterblock */
    pos = 10;                               /* start of Parameterblock */
    paramlen = 0;
    for (i = 0; i < paramCount; i++) {
        len = strlen(param[i]);
        pa[pos++] = len;                    /* 1 Byte stringlength */
        memcpy(&pa[pos], param[i], len);    /* the string */
        pos += len;
        if (len % 2 == 0) {                 /* stringlength + length header must be even */
            pa[pos++] = '\0';               /* fillbyte */
            paramlen += 1 + len + 1;
        } else {
            paramlen += 1 + len;
        }
    }
    /* set parameter block length */
    pa[8] = paramlen / 256;
    pa[9] = paramlen % 256;

    /* add servicename */
    len = strlen(piservice);
    pa[pos++] = len;
    memcpy(&pa[pos], piservice, len);
    pos += len;

    /* length of complete parameter part */
    len = 10 + paramlen + 1 + strlen(piservice);

    p.header=dc->msgOut+dc->PDUstartO;
    _daveInitPDUheader(&p, 1);
    _daveAddParam(&p, pa, len);

    ((PDUHeader2*)p.header)->plenHi = p.plen / 256;
    ((PDUHeader2*)p.header)->plenLo = p.plen % 256;

    res =_daveExchange(dc, &p);
    if (res == daveResOK) {
        res =_daveSetupReceivedPDU(dc, &p2);
        if (daveDebug & daveDebugPDU) {
            _daveDumpPDU(&p2);
        }
    }
    return res;
}
```
libnodave typisch wird nichts überprüft, d.h. wer in die Funktion falsche Parameter eingibt, der muss mit einem Absturz rechnen.
Einzelne Strings dürfen nicht länger als 253 sein. Laut Dokumentation der PI-Dienste dürfen die meisten nur wesentlich kürzer sein.

Aufrufen der Funktion dann mit:

```
const char *pistart_parameter[] = {
    "P01",
    "_N_MPF_DIR/_N_TEILEPROG2_MPF",
    ""
};

res = davePIstart_nc(dc, "_N_F_OPEN", pistart_parameter, 3);
```
Das könnte man ja so als Low-Level Schnittstelle in der Bibliothek stehen lassen. Ein String-Array als Parameter sollte sich auch relativ einfach in .Net verwenden lassen, zumindest einfacher als eine variadische Funktion.


----------



## Hans54216 (25 April 2016)

Danke für den Code!!!

Hab gerade die ersten PI-Service per libnodave verschickt.

Hast du eine Beschreibung zu den File Diensten? "_N_F_OPEN", "_N_F_CLOSE" ...

Wie weit bist du mit der Implementierung in WireShark?


----------



## Thomas_v2.1 (25 April 2016)

Die Beschreibungen zu den PI-Diensten habe ich aus der Hilfedatei für das WinCCflexible Sinumerik Addon, das jemand hier https://support.industry.siemens.co...meters-information/106222/?page=0&pageSize=10 angehängt hat.
Dort sind die beiden von dir genannten enthalten, und diverse andere auch. So wie es aussieht gibt es wohl auch Codebeispiele, die aber in der Hilfedatei nicht vorhanden sind. Da müsste man schon jemanden fragen, der dieses Addon wirklich gekauft hat ob der einen da mal einen Blick reinwerfen lässt.
Meiner Meinung nach ist zumindest für einen PI-Dienst ein Fehler in der Beschreibung (_N_DZERO), weil die Dienstnamen immer eine ungerade Länge haben. Ich habe dann mal angenommen, das verlängert sich zu _N_DZERO_.

Ich habe alles soweit in Wireshark drin. Aber ich mache das ja nicht mehr mit einer separaten plugin-dll, sondern das wird dann direkt in Wireshark eingepflegt. Darum sollte das dann auch möglichst zu 100% (oder zumindest 99%) passen. Dann muss der Patch bei Wireshark noch durch den Codereview-Prozess, und das kann dauern. Außerdem muss ich durch die neu gewonnenen Informationen auch ein paar andere Dinge die zur SPS-Programmierung gehören korrigieren/verbessern.
Ich könnte dir höchstens ein komplettes Verzeichnis mit allen Wireshark Dateien zur Verfügung stellen, das ist dann aber schätze ich mal 100 MByte groß.


----------



## Hans54216 (26 April 2016)

Hab das neue Wireshark ein bisschen ausprobiert. Soweit sieht´s gut aus.

Beim "NC_File_Upload", auch im Paket enthalten wird ja zunächst der PI-Dienst "_N_F_XFER" gestartet. Dieser funktioniert auch soweit.
Anschließend folgen "Start upload", "Upload", "End upload".

Der Funktionskode ist ja wie in libnodave.

```
#define daveFuncStartUpload        0x1D
#define daveFuncUpload             0x1E
#define daveFuncEndUpload          0x1F
```

Jedoch passen die Funktionen nicht zur NC. Wireshark zeigt die Funktionen teilweise falsch an. (liegt wohl an dem Unterschied zur SPS)


Kannst du mir ne angepasste Funktion für "Start upload", "Upload", "End upload" schreiben?


----------



## Thomas_v2.1 (26 April 2016)

Ich bin auch eigentlich mit der Namensgebung für Download und Upload nicht ganz glücklich. Wenn ich im Internet eine Datei von einem Webserver herunterlade, ist das ein Download. So wie das in Wireshark angezeigt und auch in libnodave verwendet wird, wäre das Übertragen von Bausteinen vom PG in die SPS ein Download. Ich weiß aber nicht ob ich das nochmal ändere.

Beim jetzigen "Upload" eines Bausteins aus einer SPS, wird der Dateistring bei StartUpload zerlegt, sodass ich direkt sehen kann welcher Baustein (Typ und Nummer) übertragen wird. Leider kann ich das auf dem Netzwerk nicht anhand irgendeiner Kennung unterscheiden, ob das eine Bausteinbezeichnung für die SPS, oder ein NC-Dateiname ist. Bei einer SPS ist der ganze Dateiname aber immer 9 Zeichen lang.
Ist dieser bei der NC fix 17 Zeichen, oder zumindest immer länger als 9? Dann könnte ich pauschal sagen, wenn 9 Zeichen lang, dann als SPS Bausteinadresse zerlegen, und sonst nur den Dateinamen anzeigen.

Die jetzigen Upload Funktionen sollten sich noch relativ einfach anpassen lassen, kann ich bei Gelegenheit mal angehen. Ich weiß aber noch nicht wann ich dazu komme, eher am Wochenende.


----------



## Thomas_v2.1 (26 April 2016)

Und noch eine Bezeichnungsfrage: NC, NCU, NCK
Welches Kürzel ist an welcher Stelle zu verwenden?
NC - Numerical Control
NCU - Numerical Control Unit
NCK - Numerical Control Kernel

Mit welchem von den dreien kommunizierst du, wenn du eine Datei überträgst, einen PI-Service aufrufst, oder eine Variable liest?


----------



## Hans54216 (26 April 2016)

Thomas_v2.1 schrieb:


> Ich bin auch eigentlich mit der Namensgebung für Download und Upload nicht ganz glücklich. Wenn ich im Internet eine Datei von einem Webserver herunterlade, ist das ein Download. So wie das in Wireshark angezeigt und auch in libnodave verwendet wird, wäre das Übertragen von Bausteinen vom PG in die SPS ein Download. Ich weiß aber nicht ob ich das nochmal ändere.
> 
> Beim jetzigen "Upload" eines Bausteins aus einer SPS, wird der Dateistring bei StartUpload zerlegt, sodass ich direkt sehen kann welcher Baustein (Typ und Nummer) übertragen wird. Leider kann ich das auf dem Netzwerk nicht anhand irgendeiner Kennung unterscheiden, ob das eine Bausteinbezeichnung für die SPS, oder ein NC-Dateiname ist. Bei einer SPS ist der ganze Dateiname aber immer 9 Zeichen lang.
> Ist dieser bei der NC fix 17 Zeichen, oder zumindest immer länger als 9? Dann könnte ich pauschal sagen, wenn 9 Zeichen lang, dann als SPS Bausteinadresse zerlegen, und sonst nur den Dateinamen anzeigen.



In der "doUploadNC" und "endUploadNC" ist pa[4]=1, bei den SPS Funktionen war dieser 0. Weiß jedoch nicht was dieser aussagt.
uc pa[]=    {0x1f,0,0,0,*1*,0,0,1};




Thomas_v2.1 schrieb:


> Die jetzigen Upload Funktionen sollten sich noch relativ einfach anpassen lassen, kann ich bei Gelegenheit mal angehen. Ich weiß aber noch nicht wann ich dazu komme, eher am Wochenende.



Hab die jetzigen Upload Funktionen soweit angepasst, dass ich nen Erfolgreichen Upload durchführen konnte.


----------



## Hans54216 (26 April 2016)

Thomas_v2.1 schrieb:


> Mit welchem von den dreien kommunizierst du, wenn du eine Datei überträgst, einen PI-Service aufrufst, oder eine Variable liest?



Siemens schreibt bei seinem PI_START(/NC, P01, _N_TEST_EDI, _N_F_CLOS)


----------



## Thomas_v2.1 (26 April 2016)

Hans54216 schrieb:


> In der "doUploadNC" und "endUploadNC" ist pa[4]=1, bei den SPS Funktionen war dieser 0. Weiß jedoch nicht was dieser aussagt.
> uc pa[]=    {0x1f,0,0,0,*1*,0,0,1};
> 
> Hab die jetzigen Upload Funktionen soweit angepasst, dass ich nen Erfolgreichen Upload durchführen konnte.



Vielleicht besteht die upload ID aus 4 Bytes, und nicht nur aus einem? Dann wären die Funktionen für den Upload zwischen SPS und NC grundsätzlich identisch.
Bei der SPS baust du den Dateinamen aus Sektion, Blocktyp, Blocknummer und Dateisystem (Aktiv/Passiv) zusammen, bei der NC gibst du einfach den Dateinamen an. Gehört bei der NC das "_N_" mit zum Dateinamen, oder ist das auch sowas wie ein Prefix?


----------



## Thomas_v2.1 (26 April 2016)

Also die UploadID besteht definitiv aus 4 Bytes.

Ich habe es gerade getestet, indem ich die 4 Bytes von der SPS auf dem Weg zum PG (Step7) mit eigenen Werten modifiziert habe. Step7 schickt daraufhin in beim nächsten Upload-Befehl diese 4 Bytes mit genau diesen Werten wieder zurück. D.h. so wie es jetzt in libnodave steht mag es zwar funktionieren, aber ist prinzipiell falsch.


----------



## Hans54216 (28 April 2016)

@Thomas_v2.1

Der Upload einer kleinen Datei hat funktioniert. Wenn ich nun eine Größere Datei von der Steuerung hochlade funktioniert dieser zwar soweit, dass der Wireshark stimmt, jedoch liefert die Funktion keine oder falsche Rückgabeparameter.

Wenn more = 0 -> alles gut
Wenn more != 0 -> Problem

Laut Wireshark sollte die Länge "len" bis auf das letzte Paket 946 lang sein. Es wird jedoch abwechselnd 942 und 0 geliefert. Wenn 0 geliefert wird ist der Buffer auch leer, jedoch nicht das PDU laut Wireshark.

Die Variable "more" liefert auch komische Werte. 1, 95, 1, 117, 1, 77, 1, 67 wobei sich die Werte != 1 auch ändern.


Wo ist mein Fehler?


```
int DECL2 doUploadNC(daveConnection * dc, int * more, uc**buffer, int * len, int uploadID){    PDU p1,p2;
    int res, netLen;
    p1.header=dc->msgOut+dc->PDUstartO;
    _daveConstructDoUploadNC(&p1, uploadID);
    res=_daveExchange(dc, &p1);
    if (daveDebug & daveDebugUpload) {
        LOG2("error:%d\n", res);
        FLUSH;
    }    
    *more=0;
    if(res!=daveResOK) return res;
    res=_daveSetupReceivedPDU(dc, &p2);
    *more=p2.param[1];
    if(res!=daveResOK) return res;
    //    netLen=p2.data[1] /* +256*p2.data[0]; */ /* for long PDUs, I guess it is so */;
    netLen=p2.data[1]+256*p2.data[0]; /* some user confirmed my guess... */;
    //if (*buffer) {
        memcpy(buffer,p2.data+4,netLen);
        *buffer+=netLen;
        if (daveDebug & daveDebugUpload) {
            LOG2("buffer:%p\n",*buffer);
            FLUSH;
        }
    //}
    *len=netLen;
    return res;
}
```


----------



## Thomas_v2.1 (28 April 2016)

Hast du mal einen Wireshark-Mitschnitt von so einem Upload einer großen Datei? Also durchgeführt mit der originalen Software.


----------



## Hans54216 (29 April 2016)

Hier der Wireshark des Uploads.

Anhang anzeigen NC_File_Big_Upload.rar


----------



## Thomas_v2.1 (29 April 2016)

Das ist bis auf den Dateinamen der bei Startupload eingefügt wird, und der aus 4 Bytes bestehenden Upload-ID doch identisch mit dem SPS Upload.

Du hast ja nur eine Funktion gezeigt, ich würde alle zugehörigen wie folgt anpassen.

```
int DECL2 initUploadNC(daveConnection *dc, char *filename, uc *uploadID){
    PDU p1,p2;
    int res;
    if (daveDebug & daveDebugUpload) {
        LOG1("****initUploadNC\n");
    }
    p1.header = dc->msgOut + dc->PDUstartO;
    _daveConstructUploadNC(&p1, filename);
    res = _daveExchange(dc, &p1);
    if (daveDebug & daveDebugUpload) {
        LOG2("error:%d\n", res);
        FLUSH;
    }
    if (res != daveResOK) return res;
    res = _daveSetupReceivedPDU(dc, &p2);
    if (res != daveResOK) return res;
    uploadID[0] = p2.param[4];
    uploadID[1] = p2.param[5];
    uploadID[2] = p2.param[6];
    uploadID[3] = p2.param[7];
    return 0;
}

int DECL2 doUploadNC(daveConnection *dc, int *more, uc **buffer, int *len, uc *uploadID){
    PDU p1,p2;
    int res, netLen;
    p1.header = dc->msgOut + dc->PDUstartO;
    _daveConstructDoUploadNC(&p1, uploadID);
    res=_daveExchange(dc, &p1);
    if (daveDebug & daveDebugUpload) {
        LOG2("error:%d\n", res);
        FLUSH;
    }
    *more = 0;
    if (res != daveResOK) return res;
    res = _daveSetupReceivedPDU(dc, &p2);
    *more = p2.param[1];
    if (res != daveResOK) return res;
    netLen = p2.data[1] + 256*p2.data[0];
    if (*buffer) {
        memcpy(*buffer, p2.data+4, netLen);
        *buffer += netLen;
        if (daveDebug & daveDebugUpload) {
            LOG2("buffer:%p\n",*buffer);
            FLUSH;
        }
    }
    *len+=netLen;
    return res;
}

int DECL2 endUploadNC(daveConnection *dc, uc *uploadID){
    PDU p1,p2;
    int res;
    
    p1.header = dc->msgOut + dc->PDUstartO;
    _daveConstructEndUploadNC(&p1, uploadID);
    res = _daveExchange(dc, &p1);
    if (daveDebug & daveDebugUpload) {
        LOG2("error:%d\n", res);
        FLUSH;
    }
    if(res != daveResOK) return res;
    res = _daveSetupReceivedPDU(dc, &p2);
    return res;
}

void DECL2 _daveConstructUploadNC(PDU *p, char *filename) {
    uc pa[260];
    memset(pa, 0, sizeof(pa));
    pa[0] = 0x1d;
    pa[8] = strlen(filename);
    memcpy(&pa[9], filename, strlen(filename));
    _daveInitPDUheader(p, 1);
    _daveAddParam(p, pa, strlen(filename) + 9);
    if (daveDebug & daveDebugPDU) {
        _daveDumpPDU(p);
    }
}

void DECL2 _daveConstructDoUploadNC(PDU *p, uc *uploadID) {
    uc pa[] = {0x1e,0,0,0,0,0,0,1};
    pa[4] = uploadID[0];
    pa[5] = uploadID[1];
    pa[6] = uploadID[2];
    pa[7] = uploadID[3];
    _daveInitPDUheader(p, 1);
    _daveAddParam(p, pa, sizeof(pa));
    if (daveDebug & daveDebugPDU) {
        _daveDumpPDU(p);
    }
}

void DECL2 _daveConstructEndUploadNC(PDU * p, uc *uploadID) {
    uc pa[] = {0x1f,0,0,0,0,0,0,1};
    pa[4] = uploadID[0];
    pa[5] = uploadID[1];
    pa[6] = uploadID[2];
    pa[7] = uploadID[3];
    _daveInitPDUheader(p,1);
    _daveAddParam(p, pa, sizeof(pa));
    if (daveDebug & daveDebugPDU) {
        _daveDumpPDU(p);
    }
}
```

Für die Upload ID musst du ausserhalb ein unsigned char Array mit 4 Elementen anlegen, quasi so:

```
unsigned char uploadID[4];
/* Verbindung aufbauen usw. */
res = initUploadNC(dc, "_N_TEST_UPLOAD_MPF", uploadID);
...
```
und diese dann in gleicher Weise an die folgenden Funktionen übergeben.


----------



## Thomas_v2.1 (1 Mai 2016)

Könntest du noch einen Mitschnitt von einem Download einer großen Datei machen, d.h. eine die mehrere PDUs benötigt? Und evtl. auch mal einen fehlerhaften Download erzeugen, wenn das irgendwie möglich ist.


----------



## Hans54216 (2 Mai 2016)

Thomas_v2.1 schrieb:


> Könntest du noch einen Mitschnitt von einem Download einer großen Datei machen, d.h. eine die mehrere PDUs benötigt? Und evtl. auch mal einen fehlerhaften Download erzeugen, wenn das irgendwie möglich ist.



Anhang anzeigen NC_File_Big_Download.rar


Das ist mal ein funktionierender Download.


----------



## Hans54216 (2 Mai 2016)

Mit dem Upload von großen Dateien hab ich noch Probleme.

Hab die Funktionen jetzt mal so eingebaut, wie du sie geschrieben hast. Problem ist aber das selbe. Unterscheiden sich ja auch nur darin, das die "uploadID" als uc[4] übergibst.

Hier mal die Funktion für den Upload.

//C#

```
int length = 0;
byte[] buffer = new byte[size];
res = _dc.daveGetNCProgram(filename, buffer, ref length);
```


```
protected static extern int daveGetNCProgram64(IntPtr dc, string filename, byte[] buffer, ref int length);
```


//nodave

```
int DECL2 daveGetNCProgram(daveConnection *dc, const char *filename, uc *buffer, int *length) {
   int res, len, more, totlen;
   unsigned char uploadID[4];
   uc *bb=(uc*)buffer;
   len=0;    totlen=0;
   //if (dc->iface->protocol==daveProtoAS511) {
   //    return daveGetS5ProgramBlock(dc, blockType, number, buffer, length);
   //}
   res=initUploadNC(dc, filename, uploadID);
    if (res!=0) return res;
   do {
       res=doUploadNC(dc, &more, &bb, &len, uploadID);
       totlen+=len;
       if (res!=0) return res;
   } while (more);
   res=endUploadNC(dc, uploadID);
   *length=totlen;
   return res;}
```

Anhang anzeigen NcBigUpload_Fehler_3.rar


Problem:
- jedes zweite Paket wird nicht richtig in den Buffer geschrieben.
- Ist der Upload zu Groß oder wird der Code nicht per Einzelschritt ausgeführt, kommt es zum Fehler: "Ein Ausnahmefehler des Typs "System.AccessViolationException" ist in DotNetSiemensPLCToolBoxLibrary.dll aufgetreten."

//######################################################

Möglichkeit 2:
initUploadNC, doSingleUploadNC, endUploadNC werden vom C# Pogramm separat aufgerufen.

Dazu hab ich die "doUploadNC" so angepasst, dass der Pointer für den Buffer nicht mehr weiter gestellt wird.
Die Idee ist, die Funktion wird solange vom C# Programm aufgerufen, bis "more == 0". Der Buffer wird jedesmal anhand der "len" wegkopiert.
Somit theoretisch unendliche Größe für Uploads möglich.

Hier besteht aber ebenfalls das Problem, das bei jedem zweiten Aufruf die "len == 0" und für "more" irgend ein Wert != 0 zurückkommt.
Es werden auch scheinbar doppelt so viele Jobs erzeugt.
-> Upload ist laut Wireshark schon fertig, da werden immer noch Jobs an nodave geschickt. Die Daten im Buffer sind auch erst bei der hälfte der Datei.
-> Auf diese zusätzlichen Jobs antwortet die NC mit Fehler, nodave liefert aber noch (jedes zweite mal) die fehlenden Daten.
-> Das ret der Funktion ist über diesen Zeitraum immer 0.

Jobs, die in ein PDU passen funktionieren!

Wireshark und Ausgabe des Buffers im Anhang: 
	

		
			
		

		
	

Anhang anzeigen NcBigUpload_Fehler_2.rar


//C#

```
do{
   System.Threading.Thread.Sleep(100);
   res = _dc.doUploadNC(out more, buffer, out len, id);
   if (res != 0)
   {
       break;
   }
   try
   {
       ret = System.Text.Encoding.Default.GetString(buffer, 0, len);                                                                                         //
       lstRetStr.Add(System.Text.Encoding.Default.GetString(buffer, 0, len));                                                                            // Siehe Anhang
       lstRet.Add(new stTest() { value = System.Text.Encoding.Default.GetString(buffer, 0, len), more = more, len = len });     //
   }    catch (Exception ex)
   {    }
   System.Threading.Thread.Sleep(100);}
while (more != 0);
```

//nodave

```
int DECL2 doSingleUploadNC(daveConnection *dc, int *more, uc *buffer, int *len, uc *uploadID){
   PDU p1,p2;
   int res, netLen;
   p1.header = dc->msgOut + dc->PDUstartO;
   _daveConstructDoUploadNC(&p1, uploadID);
   res=_daveExchange(dc, &p1);
   if (daveDebug & daveDebugUpload) {
       LOG2("error:%d\n", res);
       FLUSH;    }
   *more = 0;
   if (res != daveResOK) return res;
   res = _daveSetupReceivedPDU(dc, &p2);
   *more = p2.param[1];
   if (res != daveResOK) return res;
   netLen = p2.data[1] + 256*p2.data[0];
   if (netLen > 1024) return -1;
   //if (*buffer) {
       memcpy(buffer, p2.data+4, netLen);
       //*buffer += netLen;
       if (daveDebug & daveDebugUpload) {
           LOG2("buffer:%p\n",*buffer);
           FLUSH;        }
   //}
   *len=netLen;
   return res;
}
```


----------



## Thomas_v2.1 (2 Mai 2016)

Da läuft was auf ISO-Ebene schief.

Bei Verbindungsaufbau auf ISO-Ebene wird von libnodave eine TPDU-Größe von 512 Bytes vorgeschlagen.
Später beim Verbindungsaufbau auf S7-Kommunikationsebene wird aber eine 960 Bytes große PDU vorgeschlagen.
Wenn der Partner diese Größe wirklich akzeptiert (was bei der NC der Fall ist), muss eine PDU >512 Bytes fragmentiert übertragen werden.
Bei libnodave ist zwar eine Zusammensetzen von fragmentiert übertragenen Paketen realisiert, aber irgendwas stimmt da nicht.

Da du ja die lib von Jochen benutzt, schau mal nach ob bei ihm in der _daveReadISOPacket() ein Unterschied zur letzten libnodave ist.
Wenn nicht, dann ist da wohl ein Fehler in libnodave bei zusammensetzen.

Am saubersten wäre es aber, dass libnodave eine TPDU von 1024 vorschlägt, wenn er später auch eine 960er S7-PDU übertragen will.
Das ist in der _daveConnectPLCTCP() die Zeile mit:
0xC0,1,0x9,

die 0x9 wäre auf 0xa zu ändern. Du musst aber prüfen ob dann die ganzen internen Puffer auch groß genug sind. Oder du änderst die angeforderte S7-PDU Größe von 960 auf 480 Bytes, dann passt es auch zusammen, und es sollten keine TPDUs fragmentiert werden.

Wireshark kann die ISO-TPDUs übrigens wieder zusammensetzen (reassemblieren). Du musst es aber für das Protokoll COPT über das Menü Bearbeiten->Einstellungen aktivieren.


----------



## Jochen Kühner (2 Mai 2016)

Ich glaubeirgendwas mit dem zusammensetzen von iso paketen ist erst später in libnodave dazugekommen, weiß aber nicht ob ich das zu 100% richtig übernommen habe! kanns mir auch die nächsten tage mal anschauen! hier kams glaub dazu: https://github.com/jogibear9988/libnodave/commit/1a6f3b45a67f77c17f810c630702c0b19bbd648a
ich nutze ja aber einen fork, wo ich ein paar andere dinge gefixt habe, und routing auch über seriell/netlink/etc ermögliche


----------



## Hans54216 (3 Mai 2016)

Thomas_v2.1 schrieb:


> Am saubersten wäre es aber, dass libnodave eine TPDU von 1024 vorschlägt, wenn er später auch eine 960er S7-PDU übertragen will.
> Das ist in der _daveConnectPLCTCP() die Zeile mit:
> 0xC0,1,0x9,
> 
> die 0x9 wäre auf 0xa zu ändern. Du musst aber prüfen ob dann die ganzen internen Puffer auch groß genug sind. Oder du änderst die angeforderte S7-PDU Größe von 960 auf 480 Bytes, dann passt es auch zusammen, und es sollten keine TPDUs fragmentiert werden.



Hab jetzt mal einfach 0xa anstelle von 0x9 bei "uc b4[]", sowie "uc b4R[]" eingetragen.
Damit bekomme ich das richtige Ergebnis.

@Jochen: Kannst du dir das trotzdem noch ansehen, ob das so passt?

@Thomas: Bietet Wireshark die Möglichkeit zwei Aufzeichnungen zu vergleichen?

@Allgemein: Gibt es eine Möglichkeit den Speicher des "Buffer" dynamisch zu vergeben?


----------



## Thomas_v2.1 (3 Mai 2016)

Hans54216 schrieb:


> @Thomas: Bietet Wireshark die Möglichkeit zwei Aufzeichnungen zu vergleichen?


Welche Werte möchtest du denn vergleichen?
Wenn komplett alle Bytes, dann könntest du einen Hexdump über Wireshark erstellen, und die Dateien dann mit diff o.Ä. vergleichen.

Heydump geht über Wireshark, aber ich nehme dafür ganz gerne tshark, das ist im Wireshark Verzeichnis vorhanden, und kann über die Eingabeaufforderung aufgerufen werden. Ein Hexdump von allen s7comm-Paketen in einer Aufzeichnung erhältst du mit:

```
tshark -r C:\meincaputure.pcap -x -Y s7comm > file1hexdump.txt
```
Das Ergebnis landet dann in file1hexdump.txt.

In dem Hexdump sind aber die Bytes des gesamten Telegramms, d.h. nicht nur die Nutzlast der ISO-Protokolls (hier s7comm). Das geht leider nur wenn du in Wireshark für ein einzelnes Telegramm und den Baum "S7 Communication" klickst, und dann "Paketbytes anzeigen" wählst.


----------



## Thomas_v2.1 (3 Mai 2016)

Du kannst dir auch nur die Nutzlast des ISO-Protokolls exportieren. Dazu musst du aber vorher Wireshark starten, und das Protokoll S7COMM deaktivieren. Dann heißt das Nutzdatenfeld von cotp: data.data. Das kann man sich dann mit tshark anzeigen lassen:

```
tshark -r C:\meincapture.pcap -Y cotp -T fields -e data.data
```
Zusätzliche zu exportierende Felder kannst du mit -e feldname anhängen. Z.B. die Quell-IP-Adresse mit -e ip.src


----------



## Hans54216 (5 Mai 2016)

@Thomas_v2.1: Kannst du für den NC Programm Download auch noch die dave Funktion anpassen? ("davePutProgramBlock" -> "davePutNCProgram")

Vielen Dank schon mal für deine Hilfe!

PS: Deine aktuelle Wireshark Beta hab ich momentan im Einsatz. Bis jetzt sieht alles gut aus.


----------



## Thomas_v2.1 (5 Mai 2016)

Ich guck mir das mal an.
Wichtiger wäre wohl, dass Jochen sein "Fork" von libnodave mal auf den aktuellen Stand bringt. Features hinzufügen ist schön und gut, Fehlerbehebungen nachpflegen ist mMn aber wichtiger.


----------



## Jochen Kühner (5 Mai 2016)

Problem ist da eher das libnodave nicht mit quellcodeverwaltung entwickelt wird und man nich gescheit sieht was verändert wird! daher gibts von mir auch das libnodave repo auf github um den unterschied der versionen zu zeigen! ja, hab damals aber nicht alles übernommen, lag aber eher daran das das routing komplett anderst implementiert wurde als bei mir (mit weniger funktionen).
ist das denn im aktuellen libnodave korrekt?


----------



## Thomas_v2.1 (5 Mai 2016)

Keine Ahnung obs funktioniert, zumindest ist es vorhanden.

Du kannst dir doch in ein paar Sekunden dein diff selber bilden, ist doch nicht so dass ohne github überhaupt nichts mehr funktioniert. Und zur Not kann man sich ein lokales git-repo für libnodave anlegen, in dem man die einzelnen Versionen seit der Erstveröffentlichung nacheinander eincheckt. Dann gibt es eine vollständige Änderungs-Historie. Und das schreibe ich als git-Hasser ;-)


----------



## Thomas_v2.1 (7 Mai 2016)

Hans54216 schrieb:


> @Thomas_v2.1: Kannst du für den NC Programm Download auch noch die dave Funktion anpassen? ("davePutProgramBlock" -> "davePutNCProgram")


Wie liegt die Datei denn vor welche du downloaden möchtest? Ist das eine Textdatei auf der Festplatte? Und wenn ja, kann deren Inhalt 1:1 Byte/Zeichenweise hochgeladen werden, oder gibt es in der Datei noch eine Art Kopf?

Der noch zu erstellenden Funktion könnte man entweder den Dateinamen(inkl. Pfad) übergeben und diese liest diese selber ein, oder es wird die Datei extern eingelesen und der Funktion wird nur ein Zeiger auf den Dateiinhalt übergeben,

davePutProgramBlock kenne ich überhaupt nicht. In libnodave (der dll) ist ein Download für die SPS überhaupt nicht enthalten. Das gibt es nur in einem test-Programm.


----------



## Thomas_v2.1 (8 Mai 2016)

Habs gefunden, die davePutProgramBlock() ist nur bei Jochens Bibliothek enthalten.

@Hans54216:
Es wäre nützlich, wenn du nochmal ein paar Aufzeichnungen eines Downloads von verschieden großen Dateien erstellen könntest.

Meine Vermutung ist, dass nach der Anfrage "Request download" im 1. Byte der Antwort die Anzahl an Telegrammen steht, die ohne Abwarten einer Antwort an die NC geschickt werden dürfen (unackcount).
Also steht dort  z.B.eine 10, dann können 10 Telegramme gesendet werden, dann gibt es eine Antwort von der NC mit wieder einer neuen Anzahl, dann weitersenden usw. bis fertig.

Bei deinem großen Upload des HMI aus deinem anderen Thread passt das auch gut zusammen.

Bei deinem Anhang "NC_File_Big_Upload" gibt es aber eine Unstimmigkeit.
- Erste Antwort auf download request: NC sagt unackcount=1
- 1 Telegramm schicken, Antwort abwarten, NC sagt unackcount=18
- Es werden aber nur 8 Telegramme geschickt, dann kann man am Zeitstempel sehen, dass etwas gewartet wird, und dann kommt tatsächlich eine Antwort von der NC mit unackcount = 8
- Dann folgt aber nur noch 1 Telegramm und dann ist die Übertragung abgeschlossen

Entweder meine Interpretation des Feldes (unackcount) ist falsch, oder es muss das Verhalten per Definition zwischen den Partnern vereinbart sein (1 Telegramm schicken, abwarten, 8 Telegramme schicken, abwarten), was ich mir aber nicht wirklich vorstellen kann.


----------



## Jochen Kühner (8 Mai 2016)

davePutProgramBlock habe ich aus dem beispiel program erzeugt:

https://github.com/dotnetprojects/D.../master/externalDlls/libnodave/nodave.c#L6208


----------



## Thomas_v2.1 (8 Mai 2016)

Jochen Kühner schrieb:


> davePutProgramBlock habe ich aus dem beispiel program erzeugt:
> 
> https://github.com/dotnetprojects/D.../master/externalDlls/libnodave/nodave.c#L6208



Diese Zeilen finde ich fragwürdig:
6251:

```
memcpy(progBlock+4,buffer,maxPBlockLen);
```
und 6297:

```
memcpy(progBlock+4,buffer+(cnt*maxPBlockLen),maxPBlockLen);
```

Wenn der Buffer nicht ein Vielfaches von maxPBlockLen, wird aus ganz anderem Speicher gelesen. Der wird zwar nicht verschickt, aber das ist trotzdem nicht statthaft.
Und length als Zeiger übergeben, obwohl das überhaupt nicht notwendig ist.


----------



## Thomas_v2.1 (8 Mai 2016)

Ich habe mal die notwendigen Funktionen dafür erstellt, die zur Zeit so arbeiten wie ich es oben beschrieben habe. Wahrscheinlich wirds nicht funktionieren, wenn die NC sich so verhält wie in deinem einzigen Logfile vom Download einer großen Datei. Bei einer kleinen Datei deren Inhalt in eine PDU passt, sollte es hoffentlich funktionieren.

Es wird noch eine Funktion benötigt, die eine PDU nur absendet und nicht auf Antwort wartet. Soweit ich weiß gibt es diese noch nicht. Für TCP könnte die so aussehen:

```
/* Sendet eine PDU, ohne auf Antwort zu warten */
int DECL2 
_daveSendTCP(daveConnection *dc, PDU *p)
{
    int res, totLen, sLen;

    if (daveDebug & daveDebugExchange) {
        LOG2("%s enter _daveSendTCP\n", dc->iface->name);
    }
    dc->partPos = 0;
    totLen = p->hlen + p->plen + p->dlen;
    while (totLen) {
        if (totLen>dc->TPDUsize) {
            sLen = dc->TPDUsize;
            *(dc->msgOut + dc->partPos + 6) = 0x00;
        } else {
            sLen = totLen;
            *(dc->msgOut + dc->partPos + 6) = 0x80;
        }
        *(dc->msgOut + dc->partPos + 5) = 0xf0;
        *(dc->msgOut + dc->partPos + 4) = 0x02;
        _daveSendISOPacket(dc, 3 + sLen);
        totLen -= sLen;
        dc->partPos += sLen;
    }
    return 0;
}
```

Und die davePutNCProgram:

```
int DECL2 
davePutNCProgram(daveConnection *dc, char *filename, char *buffer, int length)
{
    PDU p, p2;
    int res = 0;
    int cnt = 0;
    int size = 0;
    uc unackcount;
    uc seq_num;
    uc dataunitref;
    int blockCont;
    int max_data_len;
    int filename_len;

    /* Request download */
    uc req_down_pa[]= {
        0x00, 0x01, 0x12, 0x04, 0x11, 0x7f, 0x01, 0x00
    };
    uc req_down_da[]= {
        0xff, 0x09, 0x00, 32,
        /* Dateiname max. 32 Zeichen */
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00
    };

    /* Download block */
    uc do_down_pa[]= {
        0x00, 0x01, 0x12, 0x08, 0x12, 0x3f, 0x02,
        0x00,       /* sequence number */
        0x00,       /* data unit reference */
        0x01,       /* Last data unit: 0=yes, 1=no */
        0x00, 0x00  /* errorcode */
    };
    /* 1920 ist die von libnodave vorgeschlagene max. PDU-Größe */
    uc do_down_da[1920 + 6]= {
        0xff, 0x09,
        0x00, 0x00, /* block size in bytes */
        0x00, 0xfb,
    };

    /* End download */
    uc end_down_pa[]= {
        0x00, 0x01, 0x12, 0x04, 0x11, 0x7f, 0x04,
        0x00       /* sequence number */
    };
    uc end_down_da[]= { 
        0xff, 0x09, 0x00, 0x02, 0x00, 0x00
    };

    filename_len = strlen(filename);    /* max. 32 chars */
    if (filename_len > 32) {
        return -1;
    }
    req_down_da[3] = filename_len;
    memcpy(&req_down_da[4], filename, filename_len);

    p.header = dc->msgOut + dc->PDUstartO;
    _daveInitPDUheader(&p, 7);
    _daveAddParam(&p, req_down_pa, sizeof(req_down_pa));
    _daveAddData(&p, req_down_da, 4 + filename_len);

    res = _daveExchange(dc, &p);
    if (res == daveResOK) {
        res = _daveSetupReceivedPDU(dc, &p2);
        if (daveGetDebug() & daveDebugPDU) {
            _daveDumpPDU(&p2);
        }
        /* Errorcode im Parameterteil prüfen */
        res = daveGetU16from(&p2.param[10]);

        if (res == 0) {
            seq_num = p2.param[9];      /* Diesen Wert für alle folgenden Downloadtelegramme verwenden */
            unackcount = p2.data[4];    /* Anzahl an Paketen die gesendet werden dürfen, ohne auf ein Ack zu warten */

            dataunitref = 0;
            do_down_pa[7] = seq_num;
            blockCont = 1;
            cnt = 0;

            /* Max. Länge in datablock = PDUsize - hlen - plen - dheader */
            max_data_len = daveGetMaxPDULen(dc) - 10 - 12 - 6;

            /* Daten senden bis unackcount = 0, dann auf Antwort warten, usw. usf. */
            do {
                do_down_pa[8] = ++dataunitref;

                p.header = dc->msgOut + dc->PDUstartO;
                _daveInitPDUheader(&p, 7);
                size = max_data_len;

                if (length > ((cnt+1) * max_data_len)) {
                    do_down_pa[9] = 1;  /* Last data unit: 1=no */
                } else {
                    size = length - (cnt * max_data_len);
                    do_down_pa[9] = 0;	/* Last data unit: 0=yes */
                    blockCont = 0;
                }
                do_down_da[2] = size / 256;
                do_down_da[3] = size % 256;

                memcpy(do_down_da + 6, buffer + (cnt * max_data_len), size);

                _daveAddParam(&p, do_down_pa, sizeof(do_down_pa));
                _daveAddData(&p, do_down_da, size + 6);
                if (daveGetDebug() & daveDebugPDU) {
                    _daveDumpPDU(&p);
                }
                if ((--unackcount > 0) || (blockCont == 0)) {
                    /* PDU senden ohne auf Antwort zu warten */
                    res = _daveSendTCP(dc, &p);
                    if (res != daveResOK) {
                        break;
                    }
                } else {
                    /* PDU senden mit Warten auf Antwort von NC */
                    LOG2("davePutNCProgram: unackcount=%d, warte auf Antwort von NC um fortzusetzen...\n", unackcount);
                    res = _daveExchange(dc, &p);
                    if (res == daveResOK) {
                        res = _daveSetupReceivedPDU(dc, &p2);
                        if (daveGetDebug() & daveDebugPDU) {
                            _daveDumpPDU(&p2);
                        }
                        /* Hier weiß ich nicht wie ein Fehler auszuwerten ist, da weder im
                         * Kopf- noch im Parameterteil ein Errorcode vorhanden ist.
                         * Bei Erfolg sollte der Datenteil 6 Bytes groß sein, und unackcount > 0
                         */

                        /*              push-nc                   continue */
                        if ((p2.param[5] == 0x3f && p2.param[6] == 0x03) &&
                           ((PDUHeader*)p2.header)->dlen == 6) {
                            unackcount = p2.data[4];    /* Anzahl an Paketen die gesendet werden dürfen, ohne auf ein Ack zu warten */
                            if (unackcount == 0) {
                                LOG2("davePutNCProgram: in continue response unackcount=%d. Exit!\n", unackcount);
                                res = daveResUnexpectedFunc;
                                break;
                            }
                        } else {
                            LOG2("davePutNCProgram: in continue response, falscher Aufbau der Antwort (p2.param[5] = %d). Exit!\n", p2.param[5]);
                            res = daveResUnexpectedFunc;
                            break;
                        }
                    } else {
                        break;
                    }
                }
                cnt++;
            } while (blockCont);

            if (res == daveResOK) {
                /* End-download senden */
                end_down_pa[7] = seq_num;
                p.header = dc->msgOut + dc->PDUstartO;
                _daveInitPDUheader(&p, 7);
                _daveAddParam(&p, end_down_pa, sizeof(end_down_pa));
                _daveAddData(&p, end_down_da, sizeof(end_down_da));
                res = _daveExchange(dc, &p);
                /* Antwort auswerten */
                if (res == daveResOK) {
                    res = _daveSetupReceivedPDU(dc, &p2);
                    if (daveGetDebug() & daveDebugPDU) {
                        _daveDumpPDU(&p2);
                    }
                    if (p2.param[5] == 0xbf && p2.param[6] == 0x05) {
                        /* Errorcode im Parameterteil prüfen */
                        res = daveGetU16from(&p2.param[10]);
                    } else {
                        res = daveResUnexpectedFunc;
                    }
                }
            }
        } else {
            LOG2("davePutNCProgram: errorcode erster Antwort: %04X\n", res);
        }
    }
    return res;
}
```

Für den Dateinamen habe ich eine maximale Länge von 32 Zeichen erlaubt. Diese Länge ist auch in der Dokumentation der PI-Services angegeben.


----------



## Hans54216 (9 Mai 2016)

Anbei noch mal nen großen Upload + Download. Diesmal direkt mit dem Siemens HMI.
Anhang anzeigen WireShark_UpDownload2.rar


----------



## Hans54216 (9 Mai 2016)

Wollte die Funktionen gerade testen. Beim compilieren kam, das "dc->partPos" und "dc->TPDUsize" fehlen.

Hab diese dann aus "libnodave-0.8.5" übernommen. (in die Struktur + in den Funktionen ("_daveExchangeTCP", "_daveSendISOPacket"))

Hat aber wohl nicht funktioniert. Kann nun keine Verbindung zur Steuerung aufbauen. Laut Wireshark wird auch kein Paket verschickt.


----------



## Thomas_v2.1 (9 Mai 2016)

Ja, das ist der Teil bei dem große S7-PDUs bei Bedarf in kleinere TPDUs gesplittet werden. Das ist bei Jochens Version nicht enthalten. Musst mal gucken wie bei ihm die daveExchangeTCP Funktion aussieht, da kannst du mehr oder weniger den ersten Code zum Senden übernehmen, und löschst nur den zweiten Teil bei dem Empfangen wird raus.

Ich teste das nur mit libnodave 0.8.5.1, da lässt sich das übersetzen, und es gehen auch Daten raus.

Aber ich kann für den Download absolut keine Logik erkennen, wann die NC nach welcher Anzahl eine Bestätigungsnachricht sendet. In deinem letzten Mitschnitt kommen diese Telegramme ja völlig unregelmäßig rein.
Insgesamt sind es 66 Telegramme zum Download. Wenn das erste Byte im Datenteil von der NC angibt wie viele Telegramme bestätigt werden, komme ich dort in Summe auf 1 + 18 + 8 + 8 + 8 + 8 + 8 + 8 + 8 + 8 = 83.
Und wenn ich annehme, die beiden Bytes geben eine Summe an Bytes an die bestätigt werden, dann komme ich auch auf keinen sinnvollen Wert.

Man muss schon wissen wann eine Antwort zu erwarten ist, andernfalls funktioniert das so nicht. Oder man muss nach jedem Senden kurz warten und gucken ob was im Empfangspuffer ist, und wenn nicht dann einfach weitersenden. Das ist aber garantiert nicht so geplant. Kann auch sein dass ich da völlig auf dem Holzweg bin.

Man könnte höchstens an einer NC mal testen, in dem man einzelne Telegramme um z.B. 2s verzögert nacheinander rausschickt, und guckt wann denn da was zurückkommt.


----------



## Thomas_v2.1 (9 Mai 2016)

Beim Download scheint es auch nochmal ein Kopfteil zu geben, zumindest wenn du dort die Datei im Archiv hochgeladen hast. Also da muss man wohl auch noch etwas voranstellen.


```
00058934160509080243    ;$PATH=/_N_WKS_DIR/_N_TEST_JE_WPD
```
Dateigröße ist 58900 Bytes.
Alle Bytes die beim Download übertragen werden sind in Summe 58958 Bytes (Netto, d.h. ohne 2 Bytes Kopf pro Datenpaket /PDU).

Wenn man den ersten Teil auftrennt in
00058934
16050908
0243 

Der hinzugefügte Kopfstring ist inkl. abschließendem Newline 58 Zeichen lang. Wie ich auch rechne komme ich nicht auf 58934. Und die anderen Zahlenwerte sagen mir auch nichts, genausowenig wie der Pfad der dort eingebaut wird.


----------



## Hans54216 (9 Mai 2016)

Thomas_v2.1 schrieb:


> ```
> 00058934160509080243    ;$PATH=/_N_WKS_DIR/_N_TEST_JE_WPD
> ```
> Und die anderen Zahlenwerte sagen mir auch nichts, genausowenig wie der Pfad der dort eingebaut wird.



Der Pfad bedeutet:
WKS.dir -> Standartverzeichnis Werkstücke
TEST_JE.wpd -> Ordnername

Was die Nummer bedeutet weiß ich nicht.


----------



## Thomas_v2.1 (9 Mai 2016)

Habs raus.
Die ersten 8 Zeichen sind Länge Dateiinhalt + Länge Pfadangabe. Alles ab ";" zählt sozusagen zu dieser Länge.
Der Rest ist der Zeitstempel der Datei:

160509080243=
09.05.2016, 08:02:43 Uhr

Den Zeitstempel zeigt zumindest auch der Windows Explorer.

Das kann ich in die Funktion noch mit einbauen. Woher soll der Zeitstempel kommen, als Parameter, oder aktuelle Zeit verwenden?

Problem ist also weiterhin nur die Anzahl an Telegrammen nach denen auf eine Antwort von der NC zu warten ist.


----------



## Hans54216 (11 Mai 2016)

Thomas_v2.1 schrieb:


> Den Zeitstempel zeigt zumindest auch der Windows Explorer.
> 
> Das kann ich in die Funktion noch mit einbauen. Woher soll der Zeitstempel kommen, als Parameter, oder aktuelle Zeit verwenden?.



Am schönsten ist es, wenn der Zeitstempel der Funktion als Parameter übergeben wird. Dann hat die Datei in der NC den selben Zeitstempel wie das Original.


----------



## Thomas_v2.1 (11 Mai 2016)

Jetzt kannst du den Pfad und den Zeitstempel als Parameter übergeben. Der Zeitstempel wird als Zeiger auf eine struct tm (aus time.h) übergeben. In C ist das Standard, aber du willst es ja in .Net benutzen. Alternativ könnte man den Zeitstempel auch als String übergeben, dann muss der Anwender aber wissen wie das Format auszusehen hat.

```
int DECL2 
davePutNCProgram(daveConnection *dc, char *filename, char *pathname, struct tm *ts, char *buffer, int length)
{
    PDU p, p2;
    int res = 0;
    int size = 0;
    uc unackcount = 0;
    uc seq_num = 0;
    uc dataunitref = 0;
    int max_data_len = 0;
    int filename_len = 0;
    int prefix_len = 0;
    int buffer_pos = 0;
    int tot_len = 0;

    /* Request download */
    uc req_down_pa[]= {
        0x00, 0x01, 0x12, 0x04, 0x11, 0x7f, 0x01, 0x00
    };
    uc req_down_da[]= {
        0xff, 0x09, 0x00, 32,
        /* Dateiname max. 32 Zeichen */
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00
    };

    /* Download block */
    uc do_down_pa[]= {
        0x00, 0x01, 0x12, 0x08, 0x12, 0x3f, 0x02,
        0x00,       /* sequence number */
        0x00,       /* data unit reference */
        0x01,       /* Last data unit: 0=yes, 1=no */
        0x00, 0x00  /* errorcode */
    };
    /* 1920 ist die von libnodave vorgeschlagene max. PDU-Größe */
    uc do_down_da[1920 + 6]= {
        0xff, 0x09,
        0x00, 0x00, /* block size in bytes */
        0x00, 0xfb,
    };

    /* End download */
    uc end_down_pa[]= {
        0x00, 0x01, 0x12, 0x04, 0x11, 0x7f, 0x04,
        0x00       /* sequence number */
    };
    uc end_down_da[]= { 
        0xff, 0x09, 0x00, 0x02, 0x00, 0x00
    };

    filename_len = strlen(filename);    /* max. 32 chars */
    if (filename_len > 32) {
        return -1;
    }
    req_down_da[3] = filename_len;
    memcpy(&req_down_da[4], filename, filename_len);

    p.header = dc->msgOut + dc->PDUstartO;
    _daveInitPDUheader(&p, 7);
    _daveAddParam(&p, req_down_pa, sizeof(req_down_pa));
    _daveAddData(&p, req_down_da, 4 + filename_len);

    res = _daveExchange(dc, &p);
    if (res == daveResOK) {
        res = _daveSetupReceivedPDU(dc, &p2);
        if (daveGetDebug() & daveDebugPDU) {
            _daveDumpPDU(&p2);
        }
        /* Errorcode im Parameterteil prüfen */
        res = daveGetU16from(&p2.param[10]);
        if (res == 0) {
            seq_num = p2.param[9];      /* Diesen Wert für alle folgenden Downloadtelegramme verwenden */
            unackcount = p2.data[4];    /* Anzahl an Paketen die gesendet werden dürfen, ohne auf ein Ack zu warten */
            do_down_pa[7] = seq_num;
            /* Max. Länge in datablock = PDUsize - hlen - plen - dheader */
            max_data_len = daveGetMaxPDULen(dc) - 10 - 12 - 6;
            do_down_da[6] = '/0';
            sprintf(do_down_da + 6, "%08d%02d%02d%02d%02d%02d%02d    ;$PATH=%s\n", 
                length + strlen(pathname) + 8, /* ;$PATH= + \n */
                ts->tm_year % 100, ts->tm_mon + 1, ts->tm_mday, ts->tm_hour, ts->tm_min, ts->tm_sec,
                pathname);
            prefix_len = strlen(do_down_da + 6);
            tot_len = prefix_len + length;
            /* Daten senden bis unackcount = 0, dann auf Antwort warten, usw. usf. */
            while (tot_len) {
                do_down_pa[8] = ++dataunitref;
                p.header = dc->msgOut + dc->PDUstartO;
                _daveInitPDUheader(&p, 7);
                if (tot_len > max_data_len) {
                    size = max_data_len;
                    do_down_pa[9] = 1;  // Last data unit: 1=no
                } else {
                    size = tot_len;
                    do_down_pa[9] = 0;	// Last data unit: 0=yes
                }
                memcpy(do_down_da + 6 + prefix_len, buffer + buffer_pos, size - prefix_len);
                tot_len -= size;
                buffer_pos += size - prefix_len;
                prefix_len = 0;
                do_down_da[2] = (size+2) / 256;
                do_down_da[3] = (size+2) % 256;

                _daveAddParam(&p, do_down_pa, sizeof(do_down_pa));
                _daveAddData(&p, do_down_da, size + 6);
                if (daveGetDebug() & daveDebugPDU) {
                    _daveDumpPDU(&p);
                }
                if (--unackcount > 0) {
                    /* PDU senden ohne auf Antwort zu warten */
                    res = _daveSendTCP(dc, &p);
                    if (res != daveResOK) {
                        break;
                    }
                } else {
                    /* PDU senden mit Warten auf Antwort von NC */
                    LOG2("davePutNCProgram: unackcount=%d, warte auf Antwort von NC um fortzusetzen...\n", unackcount);
                    res = _daveExchange(dc, &p);
                    if (res == daveResOK) {
                        res = _daveSetupReceivedPDU(dc, &p2);
                        if (daveGetDebug() & daveDebugPDU) {
                            _daveDumpPDU(&p2);
                        }
                        /* Hier weiß ich nicht wie ein Fehler auszuwerten ist, da weder im
                         * Kopf- noch im Parameterteil ein Errorcode vorhanden ist.
                         * Bei Erfolg sollte der Datenteil 6 Bytes groß sein, und unackcount > 0
                         */

                        /*              push-nc                   continue */
                        if ((p2.param[5] == 0x3f && p2.param[6] == 0x03) &&
                           ((PDUHeader*)p2.header)->dlen == 6) {
                            unackcount = p2.data[4];    /* Anzahl an Paketen die gesendet werden dürfen, ohne auf ein Ack zu warten */
                            if (unackcount == 0) {
                                LOG2("davePutNCProgram: in continue response unackcount=%d. Exit!\n", unackcount);
                                res = daveResUnexpectedFunc;
                                break;
                            }
                        } else {
                            LOG2("davePutNCProgram: in continue response, falscher Aufbau der Antwort (p2.param[5] = %d). Exit!\n", p2.param[5]);
                            res = daveResUnexpectedFunc;
                            break;
                        }
                    } else {
                        break;
                    }
                }
            };

            if (res == daveResOK) {
                /* End-download senden */
                end_down_pa[7] = seq_num;
                p.header = dc->msgOut + dc->PDUstartO;
                _daveInitPDUheader(&p, 7);
                _daveAddParam(&p, end_down_pa, sizeof(end_down_pa));
                _daveAddData(&p, end_down_da, sizeof(end_down_da));
                res = _daveExchange(dc, &p);
                /* Antwort auswerten */
                if (res == daveResOK) {
                    res = _daveSetupReceivedPDU(dc, &p2);
                    if (daveGetDebug() & daveDebugPDU) {
                        _daveDumpPDU(&p2);
                    }
                    if (p2.param[5] == 0xbf && p2.param[6] == 0x05) {
                        /* Errorcode im Parameterteil prüfen */
                        res = daveGetU16from(&p2.param[10]);
                    } else {
                        res = daveResUnexpectedFunc;
                    }
                }
            }
        } else {
            LOG2("davePutNCProgram: errorcode erster Antwort: %04X\n", res);
        }
    }
    return res;
}
```

Wahrscheinlich musst du in der nodave.h noch die time.h includieren.


----------



## Jochen Kühner (11 Mai 2016)

Was benutzt denn "daveSetPLCTime" für ein Format? Vlt. sollte man das gleich halten?

@Thomas
Ich schau morgen mal nach den von dir angesprochen Punkten


----------



## Hans54216 (12 Mai 2016)

Ich hab zum Testen die Funktion so umgebaut, das das Datum als String übergeben wird. (dt.ToString("yyMMddHHmmss"))
Scheint aber nicht zu funktionieren.  (Wireshark im Anhang)
Kopfzeile wird an den Schluss geschrieben. 
filename und Datum fehlt -> woher weiß sprintf bei ("%s", Pointer) die länge des Strings?



```
int DECL2 davePutNCProgram(daveConnection *dc, char *filename, char *pathname, uc *ts, char *buffer, int length)
...
//sprintf(do_down_da + 6, "%08d%02d%02d%02d%02d%02d%02d    ;$PATH=%s\n", 
//    length + strlen(pathname) + 8, /* ;$PATH= + \n */
//    ts->tm_year % 100, ts->tm_mon + 1, ts->tm_mday, ts->tm_hour, ts->tm_min, ts->tm_sec,
//    pathname);

sprintf(do_down_da + 6, "%08d%s    ;$PATH=%s\n", length + strlen(pathname) + 8, ts, pathname);
...
```

Anhang anzeigen dave_NC_File_Download1.rar


----------



## Thomas_v2.1 (12 Mai 2016)

In C sind Strings Nullterminiert. D.h. solange ab der Adresse auf die Pointer zeigt ein Zeichen ungleich '\0' vorhanden ist, werden die Zeichen in den String vom ersten Parameter von sprintf kopiert.

Wenn ich die Funktion so wie von dir beschrieben umbaue, dann funktioniert das wenn ich diese in C mit z.B.

```
res = davePutNCProgram2(dc, "_N_TEILEPROG3_MPF", "_N_MPF_DIR", "160422175457", buffer, 512);
```
aufrufe.

Ich habe das jetzt einfach mal so getestet, indem ich die Telegramme an eine SPS sende, aber die Abfragen ob der Austausch erfolgreich war "überbrückt" habe. Darum kann ich sehen was zumindest theoretisch rausgeht.

Bei deiner Aufzeichnung ist auch seltsam, dass bei dir zweimal hintereinander ein Request-Download angefordert wird. Bei mir ist das nicht der Fall. In der Funktion davePutNCProgram() wird das auf jeden Fall nicht so gemacht.

Kannst du das nicht erstmal direkt aus einem C-Programm testen? Dann ist die zusätzliche Fehlerquelle durch die ganze .Net Schnittstelle schonmal eliminiert. Wahrscheinlich fertigt C# da irgendeinen UTF kodierten String an.


daveSetPLCTime() nimmt auch ein char array an, die dann auch direkt 1:1 so übertragen werden. Damit man diese Funktion überhaupt verwenden kann, muss man aber wissen wie der Zeitstempel aufgebaut ist der übertragen wird. Also ich weiß das nicht aus dem Kopf und müsste das auch erst nachsehen wie ich das in Wireshark programmiert habe. Im S7-Protokoll gibt es mindestens 2 unterschiedliche Zeitstempel-Formate.


----------



## Thomas_v2.1 (12 Mai 2016)

@Hans54216

Korrigiere mal diese Zeile bei mir, d.h. von [9] auf [7]

```
seq_num = p2.param[7];      /* Diesen Wert für alle folgenden Downloadtelegramme verwenden */
```
Vielleicht funktioniert dann zumindest der Download einer kleinen Datei. Denn für alle Telegramme wird die Sequenznummer aus der ersten Antwort von der NC verwendet, zumindest war das in den von dir gezeigten Aufzeichnungen so.


----------



## Hans54216 (13 Mai 2016)

Hab den Fehler von gestern gefunden. Problem war, das ich übersah dass du zusätzlich zum "filename" nun auch nen String für den "pathname" übergibst.

Mit der Änderung von gestern Abend kommt von der NC kein Fehler zurück.
Es fehlt jedoch der Befehl sowie die Quittierung "Download ended".

Wireshark im Anhang:
Kurzes Programm "Teileprog3" wird von der NC hochgeladen und anschließend als "Teileprog4" mit selbem Inhalt zur NC hinunter geladen.

dave_NC_File_Download2.pcapng -> vor der Änderung von gestern Abend
dave_NC_File_Download3.pcapng -> inc. letzter Änderung
extern_NC_File_Download2.pcapng -> Erfolgreicher up- und download

Anhang anzeigen dave_NC_File_Download2.rar


----------



## Jochen Kühner (13 Mai 2016)

Thomas_v2.1 schrieb:


> Diese Zeilen finde ich fragwürdig:
> 6251:
> 
> ```
> ...



Sollte gefixt sein: https://github.com/dotnetprojects/D...mmit/cf5ef71772887ed91ec853502d146a7184f46202


----------



## Thomas_v2.1 (13 Mai 2016)

Hans54216 schrieb:


> Hab den Fehler von gestern gefunden. Problem war, das ich übersah dass du zusätzlich zum "filename" nun auch nen String für den "pathname" übergibst.
> 
> Mit der Änderung von gestern Abend kommt von der NC kein Fehler zurück.
> Es fehlt jedoch der Befehl sowie die Quittierung "Download ended".


Hm, probiere mal folgende Änderung:

```
if (--unackcount > 0 || do_down_pa[9] == 0) {
    /* PDU senden ohne auf Antwort zu warten */
    res = _daveSendTCP(dc, &p);
    if (res != daveResOK || do_down_pa[9] == 0) {
        break;
    }
```
Dann sollte, wenn die zuletzt gesendete PDU die letzte war, nicht mehr auf eine Antwort gewartet werden, sondern direkt der Download abgeschlossen werden.

Wenn das funktioniert, könntest du mal schrittweise das Programm vergrößern, damit es über mehrere PDUs übertragen werden muss. Wird sich zeigen ob es dann auch noch funktioniert.


----------



## Hans54216 (13 Mai 2016)

Wenn ich das so anpasse siehts in Wireshark genau so aus.
Funktion bleibt aber in einer Dauerschleife, anstelle dass sie einen Fehler zurück meldet.


Wie kann ich den Code im Studio ausführen, damit ich ihn Debuggen kann?
Brauch ja zunächst die "daveConnection" zur NCU, um deine Funktion aufzurufen.


----------



## Thomas_v2.1 (13 Mai 2016)

Das heißt es wird ein "End Download" geschickt? Dann wird eigentlich nur noch auf eine Antwort von der NC gewartet, und diese ausgewertet. Wenn keine Antwort kommt, sollte es zumindest einen Timeout geben.

Bau dir doch ein paar LOG-Ausgaben ein, das ist einfacher als da den Debugger anzuklemmen (was wegen der Kommunikation eh bescheiden funktioniert).


----------



## Hans54216 (13 Mai 2016)

Thomas_v2.1 schrieb:


> Das heißt es wird ein "End Download" geschickt? Dann wird eigentlich nur noch auf eine Antwort von der NC gewartet, und diese ausgewertet. Wenn keine Antwort kommt, sollte es zumindest einen Timeout geben..



Es wird kein "End Download" geschickt. So wie ich gerade feststellte wird auch kein "Push" geschickt.

Durch die Änderung wird ja jetzt deine Funktion "_daveSendTCP" verwendet.
Diese setzt ja noch auf die variablen "TPDUsize" und "partPos" aus der Struktur.

Ist dort vielleicht der Fehler?

Anhang anzeigen dave_NC_File_Download4.rar


----------



## Thomas_v2.1 (13 Mai 2016)

Na wie sieht denn deine _daveSendTCP aus? 

Wie gesagt, bei der libnodave Variante die Jochen verwendet, sind etliche Fehlerkorrekturen von der originalen libnodave nicht enthalten.

In der dave_NC_File_Download3 aus deinem letzten Anhang gab es doch ein "Push", dann hat sich bei dir jetzt schon wieder etwas anderes geändert wenn es jetzt nicht mehr vorhanden ist.

Wenn ich bei meiner Variante (Basis libnodave 0.8.5.1 = letzte Version) die Abfragen für die Antworten der NC auskommentiere, läuft der Download (in eine SPS) so durch, d.h. es werden zumindest alle Telegramme passend rausgeschickt.

Ich würde mir einfach an mehreren Stellen Log-Ausgaben oder printf einbauen, dann sieht man doch sofort wo es hakt.


----------



## Thomas_v2.1 (13 Mai 2016)

Ändere auch mal diese Zeile 

```
while (tot_len > 0) {
```
falls tot_len negativ werden sollte (was normal nicht sein sollte). Oder lass dir tot_len mit printf ausgeben.


----------



## Hans54216 (13 Mai 2016)

In "davePutNCProgram" verwendest du ja die Variable int tot_len.

In "_daveSendTCP" mischst du die Verwendung von "int totLen" und "tot_len"(Weiß jedoch nicht wo diese Deklariert ist).


----------



## Thomas_v2.1 (13 Mai 2016)

Kannst du in beiden Funktionen ändern, aber ich glaube nicht dass es daran liegt. Denn bei dir hat es doch schonmal bis zum 1. Push funktioniert.
 Wenn du dein _daveSendTCP auf Basis von Jochens Funktionen erstellt hast, dürfte dort der Teil mit tot_len usw. überhaupt nicht vorhanden sein. Der Teil dient dazu, wenn die TPDU < S7-PDU die S7-PDU zu fragmentieren. Wenn ich das richtig sehe, ist bei dir TPDU=1024 und S7-PDU=960, das sollte also alles ohne fragmentieren übertragen werden können.

Füge in der putNCProgramm an den entsprechenden Stellen ein:
LOG1("bin hier usw\n");
ein, und sieh dir an bis wohin ausgegeben wird. Und den debug-Level so erhöhen, dass auch alles ausgegeben wird.

Ich könnte mir ja einen NC-Simulator programmieren der sich so verhält wie eine NC um daran zu testen, aber ich weiß eben noch nicht alles genau. Es bleiben aber nicht mehr viele Felder übrig in denen sich relevante Daten verstauen lassen.


----------



## Hans54216 (13 Mai 2016)

davePutNCProgram: unackcount = 1 
davePutNCProgram: do_down_pa[9] = 0 
_daveSendTCP: totLen = 119 
_daveSendTCP: totLen = 119 
_daveSendTCP: totLen = 119 
.....


----------



## Thomas_v2.1 (13 Mai 2016)

Wie sieht denn deine _daveSendTCP aus? Das weiß ich nicht, da du ja anscheinend meine in Jochens Version nicht verwenden kannst.


----------



## Hans54216 (13 Mai 2016)

Thomas_v2.1 schrieb:


> Kannst du in beiden Funktionen ändern, aber ich glaube nicht dass es daran liegt. Denn bei dir hat es doch schonmal bis zum 1. Push funktioniert.
> Wenn du dein _daveSendTCP auf Basis von Jochens Funktionen erstellt hast, dürfte dort der Teil mit tot_len usw. überhaupt nicht vorhanden sein. Der Teil dient dazu, wenn die TPDU < S7-PDU die S7-PDU zu fragmentieren. Wenn ich das richtig sehe, ist bei dir TPDU=1024 und S7-PDU=960, das sollte also alles ohne fragmentieren übertragen werden können.



Bei "PDU senden mit Warten auf Antwort von NC" wird ein "NC Push" erzeugt.

Mit "_daveSendTCP" (/* Sendet eine PDU, ohne auf Antwort zu warten */) funkitioniert es nicht.

Die Funktion "_daveSendTCP" ist so, wie du sie geschrieben hast. Ich hab lediglich in der "struct _daveConnection" die beiden Variablen hinzugefügt.


----------



## Thomas_v2.1 (13 Mai 2016)

Kannst du die normale libnodave übersetzen? Dann hänge ich gleich mal mein Arbeitsverzeichnis an. Nicht dass wir hier über verschiedene Dinge reden.


----------



## Hans54216 (13 Mai 2016)

Thomas_v2.1 schrieb:


> Kannst du die normale libnodave übersetzen? Dann hänge ich gleich mal mein Arbeitsverzeichnis an. Nicht dass wir hier über verschiedene Dinge reden.


Weiß nicht genau was du meinst.

Hab gerade die nodave.c + nodave.h von "libnodave-0.8.5" in den Ordner vom Jochen kopiert. Beim Übersetzen kommt nun dieser Output:


----------



## Thomas_v2.1 (13 Mai 2016)

Ich hänge dir mal meine Version an. Diese Datei an beliebiger Stelle entpacken.
Wenn du das Microsoft Visual Studio installiert hast, startest du die Eingabeaufforderung für das VS command Prompt (z.B. "VS2013 x86 Native Tools Command Prompt" bei VS2013).
Auf der Konsole navigierst du dann in den Ordner in den du mein zip entpackt hast, und gibst:

nmake -f makefile.vc

ein. Dann sollte alles ordnungsgemäß kompiliert werden.
Mein Beispiel habe ich einfach mal in die testISO_TCP.c eingebaut. Das ist dann ein Download der Daten aus deinem letzten Beispiel.
Aufrufen kannst du das Programm ebenfalls über die Eingabeaufforderung mit:

testISO_TCP.exe 192.168.1.40

Als Parameter musst du die IP-Adresse übergeben. Ohne weitere Angabe wird rack=0 und slot=2 verwendet. Mit dem Parameter --slot=3 könntest du auf Slot 3 ändern. Ich weiß nicht was die NC da verlangt.


----------



## Hans54216 (13 Mai 2016)

Fehler beim Compilieren


----------



## Thomas_v2.1 (13 Mai 2016)

Schau mal in der makefile.vc ob die Pfade stimmen, dort habe ich die Pfade für die VS Version eingetragen:

VCPATH=C:\Program Files\Microsoft Visual Studio 12.0\VC
SDKPATH=C:\Program Files\Microsoft SDKs\Windows\v7.1A

Diese Pfade habe ich bei mir für VS2013 unter Windows 7 32 Bit eingetragen.

Edit:
Unter 64 Bit Windows dürfte das so etwas wie:

VCPATH=C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC
SDKPATH=C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A

sein.


----------



## Jochen Kühner (13 Mai 2016)

Ich hab die fixes von der libnodave mal übernommen. Hoffe das passt soweit! Hab aber damit noch nichts getestet!


----------



## Hans54216 (13 Mai 2016)

Mit schnell zusammenkopieren hats nicht funktioniert.

Ich schau, das ich bis Dienstag die ganzen Änderungen sauber zusammenfasse und teste anschließend weiter.


----------



## Hans54216 (17 Mai 2016)

Thomas_v2.1 schrieb:


> Ich hänge dir mal meine Version an. Diese Datei an beliebiger Stelle entpacken.
> Wenn du das Microsoft Visual Studio installiert hast, startest du die Eingabeaufforderung für das VS command Prompt (z.B. "VS2013 x86 Native Tools Command Prompt" bei VS2013).
> Auf der Konsole navigierst du dann in den Ordner in den du mein zip entpackt hast, und gibst:
> 
> ...




```
C:\Users\1\Documents\_löschen\_LibNoDave\libnodave-0.8.5.1-nc>testISO_TCP.exe 10
.172.26.233 --slot=4
Connected.
Starte PutNC Program...
davePutNCProgram: errorcode erster Antwort: 8104
davePutNCProgram res=33028
Finished.
```

Anhang anzeigen testISO_TCP_NC_File_Download1.rar


----------



## Hans54216 (17 Mai 2016)

Jochen Kühner schrieb:


> Ich hab die fixes von der libnodave mal übernommen. Hoffe das passt soweit! Hab aber damit noch nichts getestet!



Mit dieser Änderung bekomme ich keine Verbindung zur NC (Slot4). Verbundung zur PLC funktioniert.

Wireshark:
1x _myConn.Connect(); //NC (Slot4)
-> 3x Job "Setup communication" ohne Antwort

Anschließend
1x _myConn.Connect(); //PLC (Slot2)
-> 1x Job "Setup communication"
-> 1x Ack_Data "Setup communication"
-> 1x Userdata "Read SZL"
-> 1x Userdata "Read SZL"

Anhang anzeigen toolBoxConnectionErrorNC.rar


----------



## Thomas_v2.1 (17 Mai 2016)

Meine Vermutung ist, dass du dich bei meinem Testprogramm nicht mit der NC sondern mit der SPS verbindest. Dafür würde auch die PDU-Größe sprechen, die in der jetztigen Aufzeichnung 240 Bytes ist, und bei den bisherigen funktionierenden Downloads 960 Bytes (oder du hast eine andere NC die nur 240 unterstützt?).

In deinen bisherigen Aufzeichnungen von der NC-Kommunikation ist aber nie der Verbindungsaufbau zu sehen. Darum weiß ich nicht was für ein TSAP da überhaupt verwendet werden muss. Haben der Upload und die PI-Dienstaufrufe nicht mit den nodave Funktionen funktioniert? Welche TSAPs hast du dort verwendet?


----------



## Hans54216 (17 Mai 2016)

Thomas_v2.1 schrieb:


> Meine Vermutung ist, dass du dich bei meinem Testprogramm nicht mit der NC sondern mit der SPS verbindest. Dafür würde auch die PDU-Größe sprechen, die in der jetztigen Aufzeichnung 240 Bytes ist, und bei den bisherigen funktionierenden Downloads 960 Bytes (oder du hast eine andere NC die nur 240 unterstützt?).
> 
> In deinen bisherigen Aufzeichnungen von der NC-Kommunikation ist aber nie der Verbindungsaufbau zu sehen. Darum weiß ich nicht was für ein TSAP da überhaupt verwendet werden muss. Haben der Upload und die PI-Dienstaufrufe nicht mit den nodave Funktionen funktioniert? Welche TSAPs hast du dort verwendet?



TSAPs??

Die meisten Tests, vor allem die NC Up-Downloads sowie PI-Dienste hab ich an der selben NCU (Teststand 840d sl) durchgeführt.

Die Verbindung zur NC bau ich im normalerweise über die ToolBox von Jochen auf, wobei sich die PLC zur NC nur darin unterschieden, dass ich bei der NC-Verbindung den Slot auf 4 ändere.

Würde ja heißen, dass "testISO_TCP.exe 10.172.26.233 --slot=4" sich nicht mit Slot 4 verbindet.

Anhang anzeigen NC_Verbindungsaufbau.rar


----------



## Thomas_v2.1 (17 Mai 2016)

Hans54216 schrieb:


> TSAPs??


Das ist sozusagen die Zieladresse auf ISO-Ebene. Wenn du in Wireshark den Filter auf cotp.type == 0x0e einstellst, bekommst du die Anfrage zu sehen.



Hans54216 schrieb:


> Die meisten Tests, vor allem die NC Up-Downloads sowie PI-Dienste hab ich an der selben NCU (Teststand 840d sl) durchgeführt.
> 
> 
> Würde ja heißen, dass "testISO_TCP.exe 10.172.26.233 --slot=4" sich nicht mit Slot 4 verbindet.


Das stimmt, es wird weiterhin slot=2 verwendet.

Stelle den Slot mal direkt in der testISO_TCP.c ein, an der Stelle:

dc =daveNewConnection(di,2,0,useSlot);  // insert your rack and slot here

auf:

dc =daveNewConnection(di,2,0,4);  // insert your rack and slot here



Edit:
oder den slot vor der IP angeben:
testISO_TCP.exe  --slot=4 10.172.26.233


----------



## Hans54216 (17 Mai 2016)

```
C:\Users\1\Documents\_löschen\_LibNoDave\libnodave-0.8.5.1-nc>testISO_TCP.exe --slot=4 10.172.26.233
IF1 error in daveConnectPLC() step 1. retrying...
IF1 error in daveConnectPLC() step 1. retrying...
IF1 error in daveConnectPLC() step 1. retrying...
Couldn't connect to PLC.
 Please make sure you use the -2 option with a CP243 but not with CPs 343 or 443
.
```

In Wireshark sieht es jetzt genau so aus wie mit der geänderten Lib von Jochen.
Nodave bekommt keine Verbindung zur NC.

Anhang anzeigen testISO_TCP_NC_ConnectionError.rar


----------



## Thomas_v2.1 (17 Mai 2016)

Das ist wahrscheinlich noch das Problem mit der TPDU und S7-PDU Größe.

Ändere mal in der nodave.c Zeile 3812
von:

```
0xC0,1,0x9,
```
auf:

```
0xC0,1,0xa,
```

Und Zeile 1544
von:

```
dc->maxPDUlength=1920;				// assume an (unreal?) maximum
```
auf:

```
dc->maxPDUlength=960;
```


----------



## Hans54216 (17 Mai 2016)

Thomas_v2.1 schrieb:


> Das ist wahrscheinlich noch das Problem mit der TPDU und S7-PDU Größe.
> 
> Ändere mal in der nodave.c Zeile 3812
> von:
> ...


----------



## Thomas_v2.1 (17 Mai 2016)

Ja, das müsste dann auch an anderen Stellen geändert werden.

D.h. die Datei konntest du jetzt erfolgreich hochladen?

Wenn du jetzt noch in meiner Funktion in der nodave.c die Zeile 7599 von:

```
if (p2.param[5] == 0xbf && p2.param[6] == 0x05) {
```
auf

```
if (p2.param[5] == 0xbf && p2.param[6] == 0x04) {
```
änderst, sollte es auch keine Fehlermeldung mehr geben.

Dann ist zu prüfen ob und wie das bei großen Dateien funktioniert.


----------



## Jochen Kühner (17 Mai 2016)

Thomas_v2.1 schrieb:


> Das ist wahrscheinlich noch das Problem mit der TPDU und S7-PDU Größe.
> 
> Ändere mal in der nodave.c Zeile 3812
> von:
> ...



@Thomas: muß Ich das bei mir umbauen? Oder ist das nur zum testen?


----------



## Thomas_v2.1 (17 Mai 2016)

Vom Prinzip her sollte es eigentlich auch so wie jetzt funktionieren. Wenn die NC keine 1920er PDUs mag, könnte sie den Wert ja beim Aushandeln verringern. Das macht sie aber nicht, sondern beendet die Verbindung sofort. Wenn die NC kein fragmentieren von TPDUs unterstützt, könnte sie ja bei einer vorgeschlagenen TPDU-Größe von 512 die S7-PDU auf 480 festsetzen.
Ich würde zumindest die TPDU-Große in der Anfrage entsprechend hochsetzen (auf 1024) und die S7-PDU auf max. 960 in der Anfrage. Ich habe auch noch kein Siemens-Gerät gesehen, was mehr als 960er PDUs unterstützt - aber ich kenne auch nicht alle Siemens Geräte. Vielleicht ist das in der geheimen Spezifikation auch auf max. 960 festgelegt und die NC schmeißt einen zurecht raus, wer weiß.


----------



## Thomas_v2.1 (17 Mai 2016)

Vielleicht ist das auch einfach eine NC Spezialität.
Denn wenn er sich mit den gleichen Verbindungsparametern zur SPS (Rack=0, Slot=2) verbindet, akzeptiert sie diesen Wert, bzw. gibt 240 Bytes PDU beim Aushandeln zurück.
Wenn er sich hingegen zur NC (Rack=0,Slot=4) verbindet, schmeißt sie ihn mit den gleichen Daten raus.


----------



## Jochen Kühner (17 Mai 2016)

D.h. nun? Es wäre doch besser Ich ändere das, dann Funktionierts mit den PLCs und auch mit der NC, oder?


----------



## Hans54216 (17 Mai 2016)

Test mit einem großen Download.


```
C:\Users\1\Documents\_löschen\_LibNoDave\libnodave-0.8.5.1-nc>testISO_TCP.exe --
slot=4 10.172.26.233
Connected.
Starte PutNC Program...
davePutNCProgram: tot_len=4133
davePutNCProgram: unackcount=0, warte auf Antwort von NC um fortzusetzen...
davePutNCProgram: in continue response, falscher Aufbau der Antwort (p2.param[5]
 = 63). Exit!
davePutNCProgram res=-128
Finished.
```

Anhang anzeigen testISO_TCP_NC_Big_File_Download1.rar


----------



## Thomas_v2.1 (17 Mai 2016)

Ändere mal die gesamte if-Bedingung Zeile 7564/7565 auf diese eine Zeile:

```
if (p2.param[5] == 0x3f && p2.param[6] == 0x03 && p2.dlen == 6) {
```
Dann sollte eine Datei von der Größe zumindest fuktionieren.

In deinen anderen Downloads wird dann so wie es aussieht gelegentlich schon nach 8 PDUs auf eine Fortsetzungsanweisung gewartet. Vermutlich wird es ab einer Datei mit dieser Größe dann haken. Falls es dazu kommt, dann kannst du direkt mal testen was passiert wenn du in der nachfolgenden Zeile 7565:

unackcount = 8;    /* Anzahl an Paketen die gesendet werden dürfen, ohne auf ein Ack zu warten */

schreibst. Falls die Anzahl 8 nicht übermittelt wird sondern wie auch immer vereinbart wird.


----------



## Thomas_v2.1 (17 Mai 2016)

Jochen Kühner schrieb:


> D.h. nun? Es wäre doch besser Ich ändere das, dann Funktionierts mit den PLCs und auch mit der NC, oder?



Ich würde es so machen (TPDU=1024 und S7-PDU=960). Ich wüsste nichts was für die bisherigen Werte spricht. 
WinCC verwendet TPDU=1024 und S7-PDU=480, dass ein Kommunikationspartner die 960 beherrscht sehe ich bei der NC das erste mal, die 400er machen alle nur 480.


----------



## Hans54216 (18 Mai 2016)

Thomas_v2.1 schrieb:


> Ändere mal die gesamte if-Bedingung Zeile 7564/7565 auf diese eine Zeile:
> 
> ```
> if (p2.param[5] == 0x3f && p2.param[6] == 0x03 && p2.dlen == 6) {
> ...



Mit den beiden Änderungen kann ich nun auch sehr große Dateien übertragen.

Anhang anzeigen testISO_TCP_NC_Big_File_DownloadX.rar


----------



## Hans54216 (18 Mai 2016)

Habs gerade über die lib vom Jochen probiert. Funktioniert genauso.

Danke!!!

Noch zwei Dinge zum Wireshark.
1. Beim Antworten der NC auf den "NC Push" kommt "Unknown subfunc: 0x03 "
2. Einstellen eines Filters:
    - Wird der Filter vollständig eingegeben und mit "Enter" bestätigt -> alles Gut (Filter wird übernommen und Hintergrund wird grün)
    - Wird der Filter anhand der Auswahl selektiert und mit "Enter" bestätigt -> Filter wird eingetragen aber nicht aktiv, Hintergrund wird grün (man muss nun nochmals in die Filterzeile klicken und mit "Enter" bestätigen)


----------



## Thomas_v2.1 (18 Mai 2016)

Hans54216 schrieb:


> Noch zwei Dinge zum Wireshark.
> 1. Beim Antworten der NC auf den "NC Push" kommt "Unknown subfunc: 0x03 "
> 2. Einstellen eines Filters:
> - Wird der Filter vollständig eingegeben und mit "Enter" bestätigt -> alles Gut (Filter wird übernommen und Hintergrund wird grün)
> - Wird der Filter anhand der Auswahl selektiert und mit "Enter" bestätigt -> Filter wird eingetragen aber nicht aktiv, Hintergrund wird grün (man muss nun nochmals in die Filterzeile klicken und mit "Enter" bestätigen)



1. Habe ich drin. Ich habe es als "Continue download" bezeichnet. In der Version die ich dir habe zukommen lassen habe aber noch nicht.
2. Das habe ich auch schon gemerkt. Ich weiß nicht ob das einen Grund hat, dass es so gelöst wurde. Evtl. weil das Filtern bei großen Dateien schonmal etwas länger dauern kann, und man darum die Auswahl nochmal bestätigen muss? Um den GUI-Teil von Wireshark habe ich mich aber noch nie gekümmert, das ist vollständig vom Netzwerkteil abgetrennt programmiert. Darum ließ sich da auch bei der Umstellung von Gtk zu Qt relativ einfach ein neues Userinterface drüberstülpen.


Die Frage ist aber noch: Woher kommt die Anzahl 8?

Beim ersten "Continue download" kommen in den beiden Byte im Datenteil 0x12, 0x00 zurück. Das wäre 0x12=18 dez. Das funktioniert aber scheinbar nicht. Oder warum hast du das direkt auf die Konstante 8 geändert?
Danach kommt immer 0x08, 0x00. Das würde dann schön mit der 8 hinkommen und sollte dann auch funktionieren.
Da wäre meine Interpretation: Die NC sagt damit: Schick mit weitere 8 PDUs.
Aber was soll dann die 18? Oder die 8 in Telegrammen stimmt nur rein zufällig mit der Anzahl überein, und das bedeutet etwas ganz anderes.

Das sollten wir schon noch herausbekommen, andernfalls funktioniert es dann an einer anderen Anlage nicht. Außerdem möchte ich in Wireshark das Feld gerne bezeichnen, und evtl. ist das bei anderen Telegrammtypen auch so.


----------



## Hans54216 (18 Mai 2016)

Thomas_v2.1 schrieb:


> Die Frage ist aber noch: Woher kommt die Anzahl 8?
> 
> Beim ersten "Continue download" kommen in den beiden Byte im Datenteil 0x12, 0x00 zurück. Das wäre 0x12=18 dez. Das funktioniert aber scheinbar nicht. Oder warum hast du das direkt auf die Konstante 8 geändert?


Ohne die Änderung auf die Konstante 8 hat`s nicht funktioniert.

Laut testIso_DownloadHistory.txt hab ich zunächst 3 Downloads ohne die feste Konstante 8 durchgeführt.
 - Beim ersten Download (kleine Datei) hats auch funktioniert.
 - Bei den nächsten beiden (größere Datei) hat der "End download" nicht funktioniert. Damit war auch keine Datei auf der Steuerung.

Anschließend die Variable fest auf 8 gesetzt. -> Selbst riesige Downloads funktionieren.




> Danach kommt immer 0x08, 0x00. Das würde dann schön mit der 8 hinkommen und sollte dann auch funktionieren.
> Da wäre meine Interpretation: Die NC sagt damit: Schick mit weitere 8 PDUs.
> Aber was soll dann die 18? Oder die 8 in Telegrammen stimmt nur rein zufällig mit der Anzahl überein, und das bedeutet etwas ganz anderes.
> 
> Das sollten wir schon noch herausbekommen, andernfalls funktioniert es dann an einer anderen Anlage nicht. Außerdem möchte ich in Wireshark das Feld gerne bezeichnen, und evtl. ist das bei anderen Telegrammtypen auch so.



Woher die 8 kommt weiß ich nicht.


----------



## Thomas_v2.1 (18 Mai 2016)

Ja, wenn ich den Wert aus der Anwort der NC auswerte, steht da, warum auch immer, in der ersten Antwort eine 18. D.h. ich erwarte dann erst nach 18 PDUs eine Fortsetz-Anweisung von der NC, die hat aber schon eins zu viel geschickt, d.h. es steht im Empfangspuffer ein unerwartetes Telegramm.

Wenn diese einmalige 18 nicht wäre, würde alles schön zusammenpassen. Jetzt kommt: 1, 18, 8, 8, 8, 8, 8, ... usw.

Hast du Zugang zu einem anderen Typ NC, die sich evtl. anders verhält?


----------



## Hans54216 (18 Mai 2016)

Thomas_v2.1 schrieb:


> Hast du Zugang zu einem anderen Typ NC, die sich evtl. anders verhält?



Hab jetzt mal verschiedene NC-Versionen getestet.

Anhang anzeigen testISO_TCP_NC_File_unackcountTest.rar


Bei v2.6 - v4.5 kommt 1, 18, 8, 8, 8, ... -> Fehlermeldung, es wird nur der Ordner angelegt (bei "v4.5 HF2 SP4" kommt auch die Fehlermeldung, die Datei ist aber auf der Steuerung )
Bei v4.7 kommt 1, 10, 8, 8, ... -> funktioniert


----------



## Thomas_v2.1 (18 Mai 2016)

D.h. bei den Tests hast du das Festsetzen von unackount auf 8 wieder deaktiviert, also übernahme aus dem NC-Telegramm?

So wie es bei v4.7 ist hätte ich das auch erwartet. Aber wenn man bei dieser Version den Wert auf 8 festsetzen würde, dann würde es damit auch nicht funktionieren, weil (wahrscheinlich) nach 8 Telegrammen von der NC noch nichts zurückkommt.


----------



## Hans54216 (18 Mai 2016)

Thomas_v2.1 schrieb:


> D.h. bei den Tests hast du das Festsetzen von unackount auf 8 wieder deaktiviert, also übernahme aus dem NC-Telegramm?


Richtig.



> So wie es bei v4.7 ist hätte ich das auch erwartet. Aber wenn man bei dieser Version den Wert auf 8 festsetzen würde, dann würde es damit auch nicht funktionieren, weil (wahrscheinlich) nach 8 Telegrammen von der NC noch nichts zurückkommt.


unackount fest auf 8 gesetzt: funktioniert auch mit v4.7

Anhang anzeigen testISO_TCP_NC_File_unackcount8Test.rar


----------



## Thomas_v2.1 (18 Mai 2016)

Ich steh' auf dem Schlauch, mir fällt da keine Logik zu ein.

Was passiert wenn du unackcount z.B. auf 7 festsetzt? Nicht dass die NC einfach eine Zeit abwartet in der nichts kommt, und dann erst sagt "weitermachen".


----------



## Hans54216 (18 Mai 2016)

```
C:\Users\1\Documents\_löschen\_LibNoDave\libnodave-0.8.5.1-nc>testISO_TCP.exe --slot=4 192.168.214.1
Connected.
Starte PutNC Program...
davePutNCProgram: tot_len=989133
davePutNCProgram: unackcount=0, warte auf Antwort von NC um fortzusetzen...
davePutNCProgram: tot_len=988201
davePutNCProgram: Senden ohne auf Antwort zu warten, Aufruf _daveSendTCP...
davePutNCProgram: tot_len=987269
davePutNCProgram: Senden ohne auf Antwort zu warten, Aufruf _daveSendTCP...
davePutNCProgram: tot_len=986337
davePutNCProgram: Senden ohne auf Antwort zu warten, Aufruf _daveSendTCP...
davePutNCProgram: tot_len=985405
davePutNCProgram: Senden ohne auf Antwort zu warten, Aufruf _daveSendTCP...
davePutNCProgram: tot_len=984473
davePutNCProgram: Senden ohne auf Antwort zu warten, Aufruf _daveSendTCP...
davePutNCProgram: tot_len=983541
davePutNCProgram: Senden ohne auf Antwort zu warten, Aufruf _daveSendTCP...
davePutNCProgram: tot_len=982609
davePutNCProgram: unackcount=0, warte auf Antwort von NC um fortzusetzen...
davePutNCProgram res=-1025
Finished.
```


----------



## Hans54216 (18 Mai 2016)

Bei unackcount = 9 kommt zwar auch der Fehler, Datei wird aber vollständig übertragen.


----------



## Thomas_v2.1 (18 Mai 2016)

Ich könnte mir vorstellen, dass wir nach dem Absenden von EndDownload bei der Antwort von der NC nochmal prüfen, ob sich da nicht noch eine alte "Fortsetzungsanweisung" von der NC im Empfangspuffer befindet, und diese einfach wegwerfen/ignorieren. Dann kommt es hoffentlich immer zu einem erfolgreichen Abschluss.
Das ist dann zwar nicht richtig, aber es funktioniert.


----------



## Thomas_v2.1 (18 Mai 2016)

Also ab Zeile 7592 (hoffentlich sind wir da noch in sync):

```
/* Antwort auswerten */
                if (res == daveResOK) {
                    res = _daveSetupReceivedPDU(dc, &p2);
                    if (daveGetDebug() & daveDebugPDU) {
                        _daveDumpPDU(&p2);
                    }
                    while (p2.param[5] == 0x3f && p2.param[6] == 0x03 && p2.dlen == 6) {
                        /* noch ein altes Fortsetzungstelegramm im Puffer? Ignorieren und nochmal lesen */
                        LOG1("davePutNCProgram: Noch ein Fortsetzungstelegramm im Puffer, versuche nochmal zu lesen...\n");
                        res = _daveGetResponseISO_TCP(dc);
                        if (res == daveResOK) {
                            res = _daveSetupReceivedPDU(dc, &p2);
                            if (daveGetDebug() & daveDebugPDU) {
                                _daveDumpPDU(&p2);
                            }
                        }
                        if (res != daveResOK) {
                            break;
                        }
                    }
                    if (p2.param[5] == 0xbf && p2.param[6] == 0x04) {
```


----------



## Hans54216 (18 Mai 2016)

```
davePutNCProgram: tot_len=11465davePutNCProgram: Senden ohne auf Antwort zu warten, Aufruf _daveSendTCP...
davePutNCProgram: tot_len=10533
davePutNCProgram: unackcount=0, warte auf Antwort von NC um fortzusetzen...
davePutNCProgram: tot_len=9601
davePutNCProgram: Senden ohne auf Antwort zu warten, Aufruf _daveSendTCP...
davePutNCProgram: tot_len=8669
davePutNCProgram: Senden ohne auf Antwort zu warten, Aufruf _daveSendTCP...
davePutNCProgram: tot_len=7737
davePutNCProgram: Senden ohne auf Antwort zu warten, Aufruf _daveSendTCP...
davePutNCProgram: tot_len=6805
davePutNCProgram: Senden ohne auf Antwort zu warten, Aufruf _daveSendTCP...
davePutNCProgram: tot_len=5873
davePutNCProgram: Senden ohne auf Antwort zu warten, Aufruf _daveSendTCP...
davePutNCProgram: tot_len=4941
davePutNCProgram: Senden ohne auf Antwort zu warten, Aufruf _daveSendTCP...
davePutNCProgram: tot_len=4009
davePutNCProgram: Senden ohne auf Antwort zu warten, Aufruf _daveSendTCP...
davePutNCProgram: tot_len=3077
davePutNCProgram: unackcount=0, warte auf Antwort von NC um fortzusetzen...
davePutNCProgram: tot_len=2145
davePutNCProgram: Senden ohne auf Antwort zu warten, Aufruf _daveSendTCP...
davePutNCProgram: tot_len=1213
davePutNCProgram: Senden ohne auf Antwort zu warten, Aufruf _daveSendTCP...
davePutNCProgram: tot_len=281
davePutNCProgram: Senden ohne auf Antwort zu warten, Aufruf _daveSendTCP...
davePutNCProgram: tot_len=0
davePutNCProgram: Senden ohne auf Antwort zu warten, Aufruf _daveSendTCP...
davePutNCProgram: Daten sind gesendet, gehe zu 'End Download'
davePutNCProgram: Sende End download...
davePutNCProgram: End download, res=0
davePutNCProgram: Noch ein Fortsetzungstelegramm im Puffer, versuche nochmal zu
lesen...
davePutNCProgram: End download, errorcode in parameterteil war res=0
davePutNCProgram res=0
Finished.
```

Datei ist auf der Steuerung vorhanden.

Anhang anzeigen testISO_TCP_NC_File_Download8_v4_5_5_5_work.rar


----------



## Thomas_v2.1 (18 Mai 2016)

Nicht schön aber selten.
Oder wir prüfen ob in dem Telegramm von der NC eine 18 steht, und dann wird eine 8 angekommen. Wenn dort eine 10 oder 8 steht dann wird dieser Wert übernommen, denn dann scheint sich die NC auch so zu verhalten. Die v4.7 schickt zumindest die 10, und das passt dann auch.

Als Notfallbremse dann die Prüfung ob noch was im Puffer ist, für sonstige Exoten.


----------



## Thomas_v2.1 (18 Mai 2016)

So in der Art (Zeile 7566):

```
if (unackcount == 18) {
                                unackcount = 8;
                            } else if (unackcount == 0) {
                                LOG2("davePutNCProgram: in continue response unackcount=%d. Exit!\n", unackcount);
```


----------



## Hans54216 (18 Mai 2016)

Hab ich so eingebaut und getestet.


----------



## Thomas_v2.1 (18 Mai 2016)

Dann müsste man zumindest nochmal den Code "durchfegen", und die Kommunikation unabhängig von den Übertragungswegen machen. Jetzt ist ja fest Iso-On-TCP eincodiert.

Ich weiß nur noch nicht was ich in Wireshark an dieses Datenfeld (1.Byte) schreiben soll, oder ich lass es einfach ohne Beschreibung.


----------



## Hans54216 (30 Mai 2016)

Wie sieh´s bei dir aus? Hast du lust den Code unabhängig vom Übertragungsweg zu machen?

Ich kann den Code dann gerne testen.


----------



## Thomas_v2.1 (31 Mai 2016)

Hans54216 schrieb:


> Wie sieh´s bei dir aus? Hast du lust den Code unabhängig vom Übertragungsweg zu machen?
> 
> Ich kann den Code dann gerne testen.



Ich dachte du bist schon schwer dabei ;-)

Also muss ich nicht unbedingt machen, das müsste ja auch in Jochens Lib rein. Fang doch mal an, wenn's hakt dann kannst du gerne fragen.


----------



## Hans54216 (1 Juni 2016)

Thomas_v2.1 schrieb:


> Ich dachte du bist schon schwer dabei ;-)
> 
> Also muss ich nicht unbedingt machen, das müsste ja auch in Jochens Lib rein. Fang doch mal an, wenn's hakt dann kannst du gerne fragen.



Hab im Moment gerade wenig Zeit da was zu machen. Zusätzlich sehe ich Momentan keinen Anwendungsfall in dem ein anderer Übertragungsweg als Iso-On-TCP zur NC nötig ist.

Nach dem der Jochen seine Lib überarbeitete hab ich die Tests ja bereits mit dieser Durchgeführt.

Werde diese dann wohl nur optisch überarbeiten und ein Pull Request anlegen.


----------



## Jochen Kühner (1 Juni 2016)

Mach mal, vlt kann Ich's mir dann auch nochmal anschauen...


----------



## Hans54216 (2 Juni 2016)

------------


----------



## Hans54216 (20 Oktober 2016)

Kennt sich jemand von euch mit dem Siemens .ACX Format aus? Hab mir den upload des HMI angesehen. Dieses lädt wohl zur Anzeige der GUDs die GUD-Dateien im ACX Format von der Steuerung.

Anhang anzeigen FileUpload_ACX.rar


----------



## Hans54216 (26 Oktober 2016)

Falls jemand lust hat mich zu unterstützen. Hab mal ein ganzes Paket zusammengestellt, mit den meisten Datentypen und den zugehörigen Definitionsdateien.


----------



## Thomas_v2.1 (26 Oktober 2016)

Wozu dienen denn die Dateien überhaupt, und was kannst du dort hineinschreiben? Ist das dann eine Art Beschreibungssprache, wenn ja, was gibt es dort für einen Befehlssatz?


----------



## Hans54216 (27 Oktober 2016)

Wenn ich richtig liege kann damit der Inhalt der Definitionsdatei GUDx von der NC gelesen werden.
Bei der 840d gibt es Definitionsdateien für Variablen. Deren Inhalt wird erst nach dem aktivieren aktiv. Und genau hier liegt gerade mein Problem. Ich hab mir nen Interpreter für die Definitionsdatei geschrieben. Ist nun eine Datei nicht aktiviert und es wurde zwischendrin eine Variable verändert verschieben sich die Adressen für den Lese/Schreibzugriff.

Hab mir die Hexfiles heute mal genauer angesehen und auch schon einzelne Byte ausgemacht, die für den Datentyp oder Arrays stehen.

Kennst du ein Tool mit dem man die Hexfiles schön vergleichen kann?


----------



## Jochen Kühner (27 Oktober 2016)

schau dir mal den an, den ich hier : HEX Editor mit Gramatik (zur Fileanalyse) + TIA-File Format Grammar File empfohlen habe.


----------



## Lieven (31 Oktober 2016)

Wrong place


----------



## rolfdieter (4 August 2017)

Hi zusammen, 
das Thema ist leider schon etwas älter aber vielleicht finden sich hier noch einige User die mir weiterhelfen können.
Ich würde gerne von einer Siemens 840D Kanal und GUD Variablen einlesen. Der Zugriff auf Datenbausteine z.b. DB211.DBW123 funktioniert super.
Gibt es eine Möglichkeit auch "/Channel/State/progToolIdent" (aktueller Werkzeugname in Spindel) und GUD-Variablen z.b. "/NC/_N_NC_GD2_ACX/<Variablenname>" (/nck/GD2/<Variablenname>)

Vielen Dank und Grüße
Rolf


----------



## Thomas_v2.1 (5 August 2017)

Hast du ein Siemens Gerät welches diese Daten abfragen kann?
Wenn ja, dann könntest du mit Wireshark eine Aufzeichnung machen wenn du diese Daten abfragst, und diese Datei hier anhängen. Dann kann man prüfen wie die Abfrage aussieht, ob und wie das mit den bestehenden Funktionen möglich ist, oder ob da etwas zu ergänzen ist.


----------



## Hans54216 (5 August 2017)

Eine direkter Zugriff per Name ist nicht möglich.

Es steht jedoch alles was du brauchst bereits im Verlauf dieses Themas.
In der "DotNetSiemensPlcToolbox" sowie der zugehörigen LibNoDave ist bereits alles implementiert, was du für die Abfrage benötigst.

Mit dem NC-VAR-Selector kommst du an die benötigten Informationen.

Übrigens "progToolIdent" ist das Programmierte aber nicht zwangsläufig das aktuelle Werkzeug in der Spindel. Dafür gibts die "actToolIdent".

Der NC-Var-Selector liefert z.B. für actToolIdent diese Struktur die ja für den FB2(Get), FB3(Put) benötigt werden. Diese Informationen kannst du auch der "DotNetSiemensPlcToolbox" übergeben (PlcNckTag) und du bekommst den Namen.



```
C1_S_actToolIdent1:
   STRUCT
   SYNTAX_ID : BYTE := B#16#82;
   bereich_u_einheit : BYTE := B#16#41;
   spalte : WORD := W#16#21;
   zeile : WORD := W#16#1;
   bausteintyp : BYTE := B#16#7F;
   ZEILENANZAHL : BYTE := B#16#1;
   typ : BYTE := B#16#13;
   laenge : BYTE := B#16#20;
   END_STRUCT ;


 END_STRUCT ;
```

Du bekommst auch die Startadresse der GUD (Component GDx, Name Dummy )

Um die Offsets zu berechnen kannst du entweder die ACX Datei interpretieren oder du legst fest, dass immer ein Bestimmter Bereich für die GUDs verwendet werden muss (z.B. Immer GUD4 und immer in der selben Reihenfolge) dann kannst du dir das Interpretieren sparen.


----------



## rolfdieter (8 August 2017)

Hallo Hans, 
vielen Dank für deine Hilfe! Leider bekomme ich die Daten aus dem NC-Var Selector nicht in den Nck Tag. Welcher Wert aus dem Selector muss in 
welchen Parameter des Tag geschrieben werden damit das Auslesen funktioniert. 
Ich bekomme immer den Fehler "Operation failed due to error from PLC 33028: context is not supported. Step7 says:Function not implemented or error in telgram."


----------



## Hans54216 (9 August 2017)

Hab dafür noch die Klasse NC_Var geschrieben. Dieser kannst du die Werte übergeben und bekommst den PlcNckTag zurück.
Außerdem kannst du der Methode GetNckTag noch einen Offset für Zeile oder Spalte mitgeben, der z.B. für weitere Kanäle oder weitere Spindel benötigt wird. (Grundstruktur der Adressen ist ja immer gleich)


```
PLCConnection _myConn = new PLCConnection("ReadFromNck");


_myConn.Configuration.CpuIP = "192.168.214.1";
_myConn.Configuration.CpuSlot = 4;
_myConn.Connect();

var tag = new NC_Var(0x82, 0x41, 0x21, 0x1, 0x7F, 0x1, 0x13, 0x20).GetNckTag();
//var tag = new NC_Var(0x82, [FONT=arial black]0x40[/FONT], 0x21, 0x1, 0x7F, 0x1, 0x13, 0x20).GetNckTag([FONT=arial black]1[/FONT]); //Kanal
_myConn.ReadValue(tag);
```


----------



## rolfdieter (15 August 2017)

Vielen Dank! Hab es mit dem Fork der Library von Hans54216 und der genannten Klasse hinbekommen.
Gibt es schon Erfahrungen mit dem Interpretieren der ACX Files? Es wäre super wenn man über den Symbolischen Namen den Nck Tag bekommen und mit diesem dann die Werte lesen könnte.


----------



## Jochen Kühner (15 August 2017)

Habt ihr in dem Fork Änderungen welche Ich übernehmen kann bzw. soll?


----------



## Hans54216 (16 August 2017)

Hallo Jochen, mein Fork ist der von Nick135. Darin sind ein paar Erweiterungen sowie Fehlerbehebungen zum Thema NCK vorhanden. Hab bis jetzt nur noch keine Zeit, Lust gefunden nen PullRequest zu machen. Du verwendest ja eh keine 840d


----------



## Hans54216 (16 August 2017)

@rolfdieter

Ich hab dies schon in einem Projekt gemach. Muss mal schauen ob ich die einzelnen Methoden extrahieren kann.


----------



## rolfdieter (17 August 2017)

@Hans54216
Das wäre sehr interessant für mich!


----------



## Hans54216 (17 August 2017)

Mit dem Kode solltest du die GUD2 lesen können.

Bei Zeiten möchte ich das mal sauber in die Lib übernehmen. Wird aber wohl ein bisschen dauern.


```
private void abc()
        {
            PLCConnection _myConn = new PLCConnection("");
            string IPAddress = "192.168.214.1";


            try
            {
                _myConn.Configuration.CpuIP = !string.IsNullOrEmpty(IPAddress) ? IPAddress : "192.168.214.1";
                _myConn.Configuration.CpuSlot = 4;
                _myConn.Connect();


                #region ACX File laden
                byte[] bAr = _myConn.BinaryUploadFromNC("_N_NC_GD2_ACX");
                byte[] GudFile = new byte[bAr.Length - 24];
                Array.Copy(bAr, 24, GudFile, 0, GudFile.Length);
                #endregion


                #region parse
                var bArX = Separate(GudFile, new byte[] { 4, 0, 0, 0, 0 });
                List<GudVar> lGUD = new List<GudVar>();
                for (int i = 1; i < bArX.Length; i++)
                {
                    string name = string.Empty;
                    int gudIndex = 0;
                    int size = 0;
                    int dim1 = 0;
                    int dim2 = 0;
                    int dim3 = 0;
                    int[] range = new int[0];
                    GudVar.E_NCK_Type nckType = GudVar.E_NCK_Type.NULL;


                    int index = 3;
                    name = Encoding.Default.GetString(bArX[i], index, bArX[i][0]);
                    index += bArX[i][0];


                    for (int j = index; j < bArX[i].Length; j++)
                    {
                        if (bArX[i][j] == 0x20)
                        {
                            int valueBytesCount = bArX[i][j - 2];
                            var value = getValue(bArX[i], valueBytesCount, j + 1);
                            switch (bArX[i][j - 1])
                            {
                                case 0x85:  //String länge
                                    size = value;
                                    break;


                                case 0x88:  //Index der Variablen im GUD-Bereich
                                    gudIndex = value;
                                    break;


                                case 0x89:  //Datentype
                                    getNckType(value, ref size, ref nckType);
                                    break;


                                case 0x98:  //Größe Dimension1
                                    dim1 = value;
                                    break;


                                case 0x99:  //Größe Dimension2
                                    dim2 = value;
                                    break;


                                default:
                                    break;
                            }
                            j += valueBytesCount;
                        }
                        else if (bArX[i][j] == 0x25)
                        {
                            int valueBytesCount = bArX[i][j - 2];
                            var value = getValue(bArX[i], valueBytesCount, j + 1);
                            switch (bArX[i][j - 1])
                            {
                                case 0x67:  //Größe Dimension3
                                    dim3 = value;
                                    break;


                                default:
                                    break;
                            }
                            j += valueBytesCount;
                        }
                    }


                    if (dim3 != 0)
                        range = new int[] { dim1, dim2, dim3 };
                    else if (dim2 != 0)
                        range = new int[] { dim1, dim2 };
                    else if (dim1 != 0)
                        range = new int[] { dim1 };


                    GudVar gud = new GudVar(gudIndex, dim1 != 0, name, range, size, nckType);


                    lGUD.Add(gud);
                }
                #endregion


                var _gud = lGUD[0];
                var ncVar = new NC_Var(0x82, 0x1, _gud.GudNumber, (_gud.IsArray ? 0x0 : 0x1), 0x2D, 1, (int)_gud.Type, _gud.Size);
                var tag = ncVar.GetNckTag();
                _myConn.ReadValue(tag);
                var _value = tag.Value;
            }
            catch (Exception)
            {
            }
            if (_myConn != null)
            {
                if (_myConn.Connected)
                    _myConn.Disconnect();
                _myConn.Dispose();
            }
        }


        private static dynamic getValue(byte[] source, int lenth, int index)
        {
            switch (lenth)
            {
                case 1:
                    return source[index];
                case 2:
                    return BitConverter.ToInt16(source, index);
                case 4:
                    return BitConverter.ToInt32(source, index);
                case 8:
                    return BitConverter.ToInt64(source, index);
                default:
                    var bAr = new byte[lenth];
                    Array.Copy(source, index, bAr, 0, bAr.Length);
                    return bAr;
            }
        }


        private static void getNckType(byte type, ref int size, ref GudVar.E_NCK_Type nckType)
        {
            switch ((GudVar.E_NCK_AcxType)type)
            {
                case GudVar.E_NCK_AcxType.BOOL:
                    nckType = GudVar.E_NCK_Type.BOOL;
                    size = 1;
                    break;


                case GudVar.E_NCK_AcxType.INT:
                    nckType = GudVar.E_NCK_Type.INT;
                    size = 4;
                    break;


                case GudVar.E_NCK_AcxType.CHAR:
                    nckType = GudVar.E_NCK_Type.CHAR;
                    size = 1;
                    break;


                case GudVar.E_NCK_AcxType.REAL:
                    nckType = GudVar.E_NCK_Type.REAL;
                    size = 8;
                    break;


                case GudVar.E_NCK_AcxType.STRING:
                    nckType = GudVar.E_NCK_Type.STRING;
                    break;


                case GudVar.E_NCK_AcxType.AXIS:
                    nckType = GudVar.E_NCK_Type.AXIS;
                    size = 1;
                    break;


                case GudVar.E_NCK_AcxType.FRAME:
                    nckType = GudVar.E_NCK_Type.FRAME;
                    size = 1;
                    break;


                default:
                    break;
            }
        }


        public static byte[][] Separate(byte[] source, byte[] separator)
        {
            var Parts = new List<byte[]>();
            var Index = 0;
            byte[] Part;
            for (var i = 0; i < source.Length; ++i)
            {
                if (Equals(source, separator, i))
                {
                    Part = new byte[i - Index];
                    Array.Copy(source, Index, Part, 0, Part.Length);
                    Parts.Add(Part);
                    Index = i + separator.Length;
                    i += separator.Length - 1;
                }
            }
            Part = new byte[source.Length - Index];
            Array.Copy(source, Index, Part, 0, Part.Length);
            Parts.Add(Part);
            return Parts.ToArray();
        }


        static bool Equals(byte[] source, byte[] separator, int index)
        {
            for (int i = 0; i < separator.Length; ++i)
                if (index + i >= source.Length || source[index + i] != separator[i])
                    return false;
            return true;
        }



    internal class GudVar
    {
        public string Name = string.Empty;
        public E_NCK_Type Type;
        public bool IsArray;
        public int[] Range;
        public int Size;
        public ushort GudNumber;


        /// <summary>
        /// 
        /// </summary>
        /// <param name="GudNumber">Position im GUD-Bereich</param>
        /// <param name="IsArray"></param>
        /// <param name="Name"></param>
        /// <param name="Range">Anzahl an Dimensionen</param>
        /// <param name="Size"></param>
        /// <param name="Type">Datentyp</param>
        internal GudVar(int GudNumber, bool IsArray, string Name, int[] Range, int Size, E_NCK_Type Type)
        {
            this.GudNumber = (ushort)GudNumber;
            this.IsArray = IsArray;
            this.Name = Name;
            this.Range = Range;
            this.Size = Size;
            this.Type = Type;
        }


        internal enum E_NCK_AcxType
        {
            BOOL = 0x0,
            INT = 0x3,
            CHAR = 0x5,
            REAL = 0xA,
            STRING = 0xC,
            FRAME = 0xD,
            AXIS = 0xE
        }


        internal enum E_NCK_Area
        {
            NCK = 0x1,
            CHAN = 0x41 //Channel 1
            //CHAN = 0x3
        }


        internal enum E_NCK_Type
        {
            NULL = 0x0,
            BOOL = 0x1,
            AXIS = 0x2,      //???  
            FRAME = 0x2,    //???
            BYTE = 0x3,
            WORD = 0x4,
            INT = 0x5,
            DWORD = 0x6,
            DINT = 0x7,
            FLOAT = 0x8,
            REAL = 0xF,
            INT64 = 0x12,
            CHAR = 0x13,
            STRING = 0x13
            //FRAME = 0x14 //???
            //AXIS = 0x15 //???            
        }
    }
```


----------



## Jochen Kühner (17 August 2017)

Ja wäre schön wenn wir das in die lib bekommen... Fänd's nicht gut wenn du einen extra fork pflegen musst.


----------



## Hans54216 (18 August 2017)

@Jochen

Gibt´s in der Lib ne Methode, mit der ich "symbolisch" auf die SPS (317 und Step7 v5.5) zugreifen kann?
Soweit ich weiß sind die Symbole ja nur offline vorhanden. Somit müsste die Methode aus dem Projekt z.B. den DB oder FB laden und dann anhand des symbolischen Namens die Adresse liefern oder besser gleich den Wert.


----------



## Jochen Kühner (19 August 2017)

Logo. Du kannst Step 7 5.x Projekte laden, einen Datenbaustein auslesen, und es gibt eine funktion aus einer Zeile ein PlcTag objekt zu erzeugen!


----------



## Hans54216 (20 Oktober 2017)

Wir verwenden an einem Teil unserer Maschinen ein neues Bedienteil und dieses Verursacht, dass z.B. SinuComNc (Siemens) und auch mein FileUpload nicht mehr funktioniert. Der FileUpload vom Sinumeric Operate (HMI) funktioniert jedoch.

WireShark logs im Anhang

@Thomas_v2.1: Kannst du mir wieder beim anpassen der LibNoDave helfen?










Anhang anzeigen File_upload_20171020.rar


----------



## Thomas_v2.1 (20 Oktober 2017)

Hm, hatte ich die Funktion nicht schon mal irgendwo programmiert? Weil wenn Wireshark das dekodieren kann, dann muss ich mir das ja schon einmal angesehen haben.
Sind die ganzen NC-Funktionen denn schon bei Jochen in der libnodave Version, oder gibt es dazu eine andere Quelle?


----------



## Thomas_v2.1 (20 Oktober 2017)

Achso jetzt sehe ich es.
In FileUpload_Error und FileUpload_NoError wird die Upload Funktion verwendet mit der auch ein Baustein in die SPS hochgeladen werden.
FileUpload_SINUMERIK_Operate enthält hingegen die NC spezifischen Befehle, die hatten wir glaube ich schon einmal in eine libnodave kompatible Funktion gegossen.


----------



## Hans54216 (20 Oktober 2017)

Fasst. Ich hab schon mal mit dir zusammen die Funktion für die NC in die Lib vom Jochen integriert. (Nach dem späteren überarbeiten der SPS Funktion sah diese auch aus, wie die von uns erstellte für die NC)

Nun habe ich aber das Problem, dass wenn das Besagte Bedienpanel läuft die Funktion einen Fehler von der Steuerung bekommt. Daher hab ich mir den Upload des Operate angesehen und dieser funktioniert anders.

Anhang anzeigen libnodave_20171020.rar


----------



## Thomas_v2.1 (20 Oktober 2017)

Die Funktion davePutNCProgram() sollte soweit ich das sehe so funktionieren wie in FileUpload_SINUMERIK_Operate.
Hast du mal eine Aufzeichnung bei der du diese Funktion verwendest und sie nicht funktioniert?
Denn in FileUpload_Error wird diese Funktion nicht verwendet, sondern der Standard-Upload der auch für S7-Programmbausteine verwendet wird.


----------



## Jochen Kühner (20 Oktober 2017)

Thomas_v2.1 schrieb:


> Sind die ganzen NC-Funktionen denn schon bei Jochen in der libnodave Version, oder gibt es dazu eine andere Quelle?



Denke das meiste ist darin, oder? Glaube Hans hat noch ein paar Änderungen die aber nim Moment nicht kompatibel zu meiner Version sind. (oder? https://github.com/Nick135/DotNetSiemensPLCToolBoxLibrary ist doch dein github account?)


----------



## Hans54216 (20 Oktober 2017)

Thomas_v2.1 schrieb:


> Die Funktion davePutNCProgram() sollte soweit ich das sehe so funktionieren wie in FileUpload_SINUMERIK_Operate.
> Hast du mal eine Aufzeichnung bei der du diese Funktion verwendest und sie nicht funktioniert?
> Denn in FileUpload_Error wird diese Funktion nicht verwendet, sondern der Standard-Upload der auch für S7-Programmbausteine verwendet wird.



Die Funktion "davePutNcProgram" wird zum download benötigt. Zum Upload verwende ich die "daveGetNCProgram" diese ist aber eine Kombination aus initUploadNC, doUploadNC und endUploadNC.



"daveGetNCProgram" sollte daher auch auf die weiße wie "davePutNcProgram" funktionieren.


----------



## Thomas_v2.1 (20 Oktober 2017)

Jetzt bin ich im Bilde 
Ich schaue mir das mal an, sieht ja prinzipiell recht ähnlich der PutNC Funktion aus.

Ich bin gerade noch dabei die als "Malformed Packet" angezeigten Pakete aus deinem einen Logfile in Wireshark richtig zu verarbeiten. Da gibt es mal wieder eine neue Ausnahme bzw. Variante um NC-Daten zu lesen. Ist das ein neues oder älteres Gerät, oder etwas ganz exotisches?


----------



## Hans54216 (20 Oktober 2017)

"Malformed Packete" kommen immer wieder vor. Bei dem Schrieb "FileUpload_SINUMERIK_Operate" handelt es sich um die NC Version 4.7.4.1. Dies ist die neueste Offizielle Version.


----------



## Thomas_v2.1 (20 Oktober 2017)

Hans54216 schrieb:


> "Malformed Packete" kommen immer wieder vor. Bei dem Schrieb "FileUpload_SINUMERIK_Operate" handelt es sich um die NC Version 4.7.4.1. Dies ist die neueste Offizielle Version.



Ab demnächst hoffentlich nicht mehr. Was das gegenüber der anderen Lesevariante für ein Vorteil hat, als dass man da unbedingt etwas ändern musste erschließt sich mir aber auch nicht.
Wenn im ersten Datenteil bei Transport-Size 0x12 steht, dann folgen die Items als NCK-Datenbereich.


----------



## Hans54216 (20 Oktober 2017)

Scheint eine Anfrage an die NC zu sein. Im ScreenShot werden Kanal und Globale Variablen gelesen


----------



## Thomas_v2.1 (20 Oktober 2017)

Also zu diesen von mir "Push" genannten Telegrammen gibt es auch eine Antwort. Ich habe diese damals "Push" genannt, weil es bei der S7 Telegramme sind die ohne Anfrage selbstständig von der SPS versendet werden können.

Also falls die 6.131 ein Client ist und die 214.1 die NC, dann stellt der Client eine Anfrage um die angegebenen NCK-Bereiche zu lesen, und bekommt dann (ebenfalls via Push) eine Antwort darauf. Prinzipiell genau so wie es auch mit den "normalen" Job/Ack_Data Telegrammen funktioniert. Man hat damit so wie ich das sehe nichts gewonnen. Im Gegenteil sogar ist diese Variante schlechter, da der Parameterteil in diesen Telegrammen größer ist, was den Datenteil und damit die max. mögliche Anzahl an lesbaren Daten entsprechend kleiner werden lässt.


----------



## Thomas_v2.1 (21 Oktober 2017)

Ich habe mal einen Entwurf für diese Funktion geschrieben. Ich habe mich dabei an dem Logfile mit deinem "NC_File_Big_Upload2" orientiert. Bei großen Dateien werden dann z.B. 20 Telegramme gesendet die nicht bestätigt werden müssen, dann gibt es einen Fortsetzbefehl usw.
Die Funktion wird übersetzt, mehr kann ich leider nicht testen. Ich habe ein paar Debug-Ausgaben eingefügt, dann können wir hoffentlich sehen woran es ggf. hakt.

Die Buffergröße muss man vorher groß genug abschätzen. Es gibt auch keine Prüfung wie groß der Buffer ist und ob dieser evtl. zu klein ist. Bei den anderen libnodave Funktionen wird das auch nirgens geprüft, man muss also wissen was man tut.
Für length musst du einen Zeiger auf einen integer übergeben, in den dann die Gesamtlänge geschrieben wird.
Aufruf z.B. mit:
length = 0;
res = daveGetNCfile(dc, "N_TEST_UPLOAD2_MPF", buffer, &length);


```
int DECL2 
daveGetNCfile(daveConnection *dc, const char *filename, char *buffer, int *length)
{
    PDU p, p2;
    int res = 0;
    uc unackcount = 0;
    int filename_len = 0;
    int tot_len = 0;
    int part_len = 0;

    /* Request upload */
    uc req_up_pa[]= {
        0x00, 0x01, 0x12, 0x04, 0x11, 0x7f, 0x06, 0x00
    };
    uc req_up_da[]= {
        0xff, 0x09, 0x00, 32,
        /* Anzahl Telegramme die ohne ack angenommen werden = 20  */
        20, 0x00,
        /* Dateiname max. 32 Zeichen */
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00
    };

    /* Continue upload */
    uc cont_up_pa[]= {
        0x00, 0x01, 0x12, 0x04, 0x11, 0x3f, 0x08, 0x00
    };
    uc cont_up_da[]= {
        0xff, 0x09, 0x00, 0x02,
        /* Anzahl Telegramme die ohne ack angenommen werden = 20 */
        20, 0x00
    };

    *length = 0;
    filename_len = strlen(filename);    /* max. 32 chars */
    if (filename_len > 32) {
        return -1;
    }
    req_up_da[3] = filename_len + 2;    /* + 1 Byte Anzahl Telegramme + 1 Byte unbekannt */
    memcpy(&req_up_da[6], filename, filename_len);

    p.header = dc->msgOut + dc->PDUstartO;
    _daveInitPDUheader(&p, 7);
    _daveAddParam(&p, req_up_pa, sizeof(req_up_pa));
    _daveAddData(&p, req_up_da, 6 + filename_len);

    res = _daveExchange(dc, &p);
    if (res != daveResOK) {
        return res;
    }
    res = _daveSetupReceivedPDU(dc, &p2);
    if (daveGetDebug() & daveDebugPDU) {
        _daveDumpPDU(&p2);
    }
    /* Errorcode im Parameterteil prüfen */
    res = daveGetU16from(&p2.param[10]);
    LOG2("daveGetNCfile: Response start upload, param.errorcode=0x%04x\n", res);
    if (res != 0) {
        return -2;
    }
    cont_up_pa[7] = p2.param[7];      /* Sequenznummer für alle folgenden Continue-Uploads verwenden */
    LOG2("daveGetNCfile: Verwendete Sequenznummer=%d\n", cont_up_pa[7]);
    res = _daveTestResultData(&p2);
    if (daveDebug & daveDebugPDU) {
        LOG3("_daveTestReadResult() returned: %d=%s\n", res, daveStrerror(res));
    }
    if (res != daveResOK) {
        return res;
    }
    LOG2("daveGetNCfile: Response start upload, p2.udlen=%d\n", p2.udlen);
    /* Vor den eigentlichen Daten sind hier noch 2 Bytes unbekannter Funktion eingeschoben */
    part_len = p2.udlen - 2;
    if (part_len <= 0) {
        return -3;
    }
    memcpy(buffer + tot_len, p2.data + 6, part_len);
    tot_len += part_len;
    /* Wenn ab hier noch nicht alles gelesen, dann werden bis zu 20 Telegramme gesendet die 
     * nicht bestätigt werden müssen. Dann gibt es ein ack usw. usf.
     */
    while (p2.param[9] != 0) {     /* 0 = Last data unit */
        LOG2("daveGetNCfile: unackcount=%d\n", unackcount);
        /* Nach 20 Telegrammen continue Telegramm senden */
        if (++unackcount == 20) {
            _daveAddParam(&p, cont_up_pa, sizeof(cont_up_pa));
            _daveAddData(&p, cont_up_da, sizeof(cont_up_da));
            if (daveGetDebug() & daveDebugPDU) {
                _daveDumpPDU(&p);
            }
            res = _daveSendTCP(dc, &p);
            if (res != daveResOK) {
                return res;
            }
            unackcount = 0;
        }
        res = _daveGetResponseISO_TCP(dc);
        if (res != daveResOK) {
            return res;
        }
        res = _daveSetupReceivedPDU(dc, &p2);
        if (daveGetDebug() & daveDebugPDU) {
            _daveDumpPDU(&p2);
        }
        /* Errorcode im Parameterteil prüfen */
        res = daveGetU16from(&p2.param[10]);
        LOG2("daveGetNCfile: continue upload, param.errorcode=0x%04x\n", res);
        if (res != 0) {
            return -2;
        }
        res = _daveTestResultData(&p2);
        if (daveDebug & daveDebugPDU) {
            LOG3("_daveTestReadResult() returned: %d=%s\n", res, daveStrerror(res));
        }
        if (res != daveResOK) {
            return res;
        }
        LOG2("daveGetNCfile: Response start upload, p2.udlen=%d\n", p2.udlen);
        part_len = p2.udlen - 2;
        if (part_len <= 0) {
            return -3;
        }
        memcpy(buffer + tot_len, p2.data + 6, part_len);
        tot_len += part_len;
    }
    *length = tot_len;
    return res;
}
```


----------



## Hans54216 (21 Oktober 2017)

Richtig, 6.131 ist das HMI und 214.1 ist die NC.

Ich kann jetzt nur mutmaßen ob es sich hier um den Änderungsdienst der NC handelt.
Es ist möglich bei der NC einen Event auf eine Variable anzumelden. Wenn die NC den Event anlegt, überträgt sie zunächst den aktuellen Wert und später dann bei Änderung.


----------



## Thomas_v2.1 (21 Oktober 2017)

Übrigens in deinem alten Logfile wurde vorher per entsprechendem PI-Service ein Dateitransfer eingeleitet. Das scheint laut deinem neuen Logfile nicht mehr gemacht zu werden. Nur zur Info. Aber die Möglichkeit der PI-Service Funktionen sind in libnodave ja auch ergänzt worden.


----------



## Peter Gedöns (21 Oktober 2017)

@Hans 
darf ich mal fragen was das für ein Bedienteil ist das diese Probleme auslöst.

und NC Software aktuell freigegeben ist bei 4.7 SP4 HF 7 (04070407) nicht 04070401 und das ist auch nicht das neuste freigegebene das es auch schon den 4.8 SP1 HF 3 gibt


----------



## Hans54216 (21 Oktober 2017)

Es ist von der Datei abhängig, ob diese per PI-Service zunächst zum Upload angewählt werden muss oder nicht. Für NC-Programme wird dies benötigt, nicht jedoch für Binärdateien .acx. Da geht auch der PI-Dienst schief.

Danke für die Methode.
Hab jetzt mal eine Anfrage an meinen Teststand geschickt. Die (Problem) Maschine ist nicht per VPN erreichbar.

Sieht gut aus.


----------



## Thomas_v2.1 (21 Oktober 2017)

Du müsstest das Ganze dann auch mal an einer größeren Datei prüfen, d.h. wenn die Übertragung mehr als 20 Telegramme benötigt. Oder testweise die Stellen mit der 20 im Code und in den Telegrammen auf z.B. 3 herunter setzen, damit das schon eher notwendig wird.
Und auch prüfen ob alles im buffer korrekt zusammengesetzt wird.


----------



## Hans54216 (21 Oktober 2017)

Peter Gedöns schrieb:


> darf ich mal fragen was das für ein Bedienteil ist das diese Probleme auslöst.



Es handelt sich um ein Schubert Bedienpanel. Dieses hat einen Win10 Ipc und solange die Schubertdienste laufen kommt es zu den Einschränkungen.



Peter Gedöns schrieb:


> und NC Software aktuell freigegeben ist bei 4.7 SP4 HF 7 (04070407) nicht 04070401 und das ist auch nicht das neuste freigegebene das es auch schon den 4.8 SP1 HF 3 gibt



Wegen mir gibt es schon eine neuere 4.7 Version. Die 4.7.4.1 ist jedenfalls die Neueste von uns eingesetzt Version und auf dieser Version Basierend sind auch Betaversionen im Einsatz um Siemens Fehler zu finden.


----------



## Hans54216 (21 Oktober 2017)

Beim Laden von Großen Dateien kommt es zum Fehler mit dem Rückgabewert -2.

Der Markierte Bereich befand sich auch im Puffer.




Anhang anzeigen daveGetNcFile_BigUpload_Error.rar


----------



## Peter Gedöns (21 Oktober 2017)

Hans54216 schrieb:


> Es handelt sich um ein Schubert Bedienpanel. Dieses hat einen Win10 Ipc und solange die Schubertdienste laufen kommt es zu den Einschränkungen.



Läuft das Operate auch auf dem Win10 IPC ?


----------



## Thomas_v2.1 (21 Oktober 2017)

Hans54216 schrieb:


> Beim Laden von Großen Dateien kommt es zum Fehler mit dem Rückgabewert -2.


Ok, die erste Antwort zählt wohl nicht zu den unacked Telegrammen dazu. Wobei dann eigentlich ein Timeout hätte kommen müssen.

Probier die Schleife mal so:

```
while (p2.param[9] != 0) {     /* 0 = Last data unit */
        LOG2("daveGetNCfile: unackcount=%d\n", unackcount);
        /* Nach 20 Telegrammen continue Telegramm senden */
        if (unackcount == 20) {
            p.header = dc->msgOut + dc->PDUstartO;
            _daveInitPDUheader(&p, 7);
            _daveAddParam(&p, cont_up_pa, sizeof(cont_up_pa));
            _daveAddData(&p, cont_up_da, sizeof(cont_up_da));
            if (daveGetDebug() & daveDebugPDU) {
                _daveDumpPDU(&p);
            }
            res = _daveSendTCP(dc, &p);
            if (res != daveResOK) {
                return res;
            }
            unackcount = 0;
        }
        res = _daveGetResponseISO_TCP(dc);
        if (res != daveResOK) {
            return res;
        }
        res = _daveSetupReceivedPDU(dc, &p2);
        if (daveGetDebug() & daveDebugPDU) {
            _daveDumpPDU(&p2);
        }
        /* Errorcode im Parameterteil prüfen */
        res = daveGetU16from(&p2.param[10]);
        LOG2("daveGetNCfile: continue upload, param.errorcode=0x%04x\n", res);
        if (res != 0) {
            return -4;
        }
        res = _daveTestResultData(&p2);
        if (daveDebug & daveDebugPDU) {
            LOG3("_daveTestReadResult() returned: %d=%s\n", res, daveStrerror(res));
        }
        if (res != daveResOK) {
            return res;
        }
        LOG2("daveGetNCfile: Response start upload, p2.udlen=%d\n", p2.udlen);
        part_len = p2.udlen - 2;
        if (part_len <= 0) {
            return -5;
        }
        memcpy(buffer + tot_len, p2.data + 6, part_len);
        tot_len += part_len;
        unackcount++;
    }
```


----------



## Hans54216 (21 Oktober 2017)

Neuer Rückgabewert ist -4

Anhang anzeigen daveGetNcFile_BigUpload_Error2.rar


----------



## Hans54216 (21 Oktober 2017)

Peter Gedöns schrieb:


> Läuft das Operate auch auf dem Win10 IPC ?



Nein. Es läuft das Embedded HMI auf der 840D sl und der IPC schaut per VNC drauf.


----------



## Thomas_v2.1 (21 Oktober 2017)

Kannst du mal  die daveDebug einschalten und die Ausgaben in eine Textdatei kopieren und anhängen?

Wenn die 4 Telegramme aus deinem Screenshot im Buffer landen, dann sieht es irgendwie so aus als ob die unterlagerten libnodave-Funktionen ein Problem damit haben, wenn mehrere S7comm-Pakete in einem TCP Telegramm vorhanden sind.
Du könntest mal testweise an den Stellen wo der Wert 20 eingetragen ist eine 1 einsetzen. Dann sollte es nach jedem Telegramm von der NC ein Continue-Telegramm von libnodave geben.
Die drei Stellen sind in req_up_da, cont_up_da und in der Abfrage if (unackcount == 20) {. 
Oder du setzt an den Stellen ein #define:
#define MAXUNACKED 1

und dann an allen Stellen MAXUNACKED einsetzen.


----------



## Hans54216 (21 Oktober 2017)

Wenn ich MAXUNACKED auf 1 setze funktionierts. Wenn ich DEBUG_CALLS einkommentiere funktioniert das Kompilieren nicht. Hab aber gesehen, dass in der Ausgabe von VS auch was zu sehen ist.


```
daveGetNCfile: Response start upload, param.errorcode=0x0000
daveGetNCfile: Verwendete Sequenznummer=71
daveGetNCfile: Response start upload, p2.udlen=934
daveGetNCfile: unackcount=0
daveGetNCfile: continue upload, param.errorcode=0x0000
daveGetNCfile: Response start upload, p2.udlen=934
daveGetNCfile: unackcount=1
daveGetNCfile: continue upload, param.errorcode=0x0000
daveGetNCfile: Response start upload, p2.udlen=934
daveGetNCfile: unackcount=2
daveGetNCfile: continue upload, param.errorcode=0x0000
daveGetNCfile: Response start upload, p2.udlen=934
daveGetNCfile: unackcount=3
daveGetNCfile: continue upload, param.errorcode=0x0000
daveGetNCfile: Response start upload, p2.udlen=934
daveGetNCfile: unackcount=4
daveGetNCfile: continue upload, param.errorcode=0x0000
daveGetNCfile: Response start upload, p2.udlen=934
daveGetNCfile: unackcount=5
daveGetNCfile: continue upload, param.errorcode=0x0000
daveGetNCfile: Response start upload, p2.udlen=934
daveGetNCfile: unackcount=6
daveGetNCfile: continue upload, param.errorcode=0x340d
```


----------



## Thomas_v2.1 (21 Oktober 2017)

Ich meinte per daveSetDebug das Debugging in libnodave aktivieren, dann werden auch ggf. die gesamten PDUs gedumpt.
Vielleicht kommt man dann zusammen mit einem Wireshark log dahinter woran es hakt. Denn es sieht so aus als ob das Problem auftritt wenn mehrere PDUs in einem Telegramm vorhanden sind. Das sollten aber die unterlagerten Funktionen von libnodave eigentlich korrekt verarbeiten können. Bei der normalen S7-Kommunikation kommt dieser Fall aber nie vor, zumindest nicht wenn man beim Verbindungsaufbau mit der SPS angibt, dass man nur ein Telegramm zur Zeit verarbeiten kann.


----------



## Hans54216 (21 Oktober 2017)

Wenn ich daveSetDebug(0x1ffff); setze funktioniert der Upload. Habs dann nochmal mit daveSetDebug(0) probiert. Dann kommt wieder Fehler -4.

Anhang anzeigen daveGetNcFile_BigUpload_Debug.rar


----------



## Thomas_v2.1 (21 Oktober 2017)

Das ist gediegen. Meine Vermutung ist aber, dass es mit debug funktioniert weil das Programm durch die debug-Ausgaben entsprechend langsamer arbeitet. Aber an welcher Stelle das Problem liegt sehe ich so nicht, _daveReadISOPacket() sollte so wie es aussieht damit klarkommen wenn mehrere PDUs in einem Telegramm sind.

Speicherst du die Ausgaben mittels einer Pipe in eine Textdatei, oder lässt du dir das auf der Konsole ausgeben? Mit einer Pipe wird es vlt. etwas schneller, sodass wir damit auch debug-Ausgaben bekommen sollten wenn der Fehler auftritt.

Ich habe mal ein paar von meinen PDU-Dumps entfernt, die sind nämlich doppelt weil in einigen Funktionen auch schon gedumpt wird. Bereinigt also:

```
#define MAXUNACKED 20
int DECL2 
daveGetNCfile(daveConnection *dc, const char *filename, char *buffer, int *length)
{
    PDU p, p2;
    int res = 0;
    uc unackcount = 0;
    int filename_len = 0;
    int tot_len = 0;
    int part_len = 0;

    /* Request upload */
    uc req_up_pa[]= {
        0x00, 0x01, 0x12, 0x04, 0x11, 0x7f, 0x06, 0x00
    };
    uc req_up_da[]= {
        0xff, 0x09, 0x00, 32,
        /* Anzahl Telegramme die ohne ack angenommen werden = 20  */
        MAXUNACKED, 0x00,
        /* Dateiname max. 32 Zeichen */
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00
    };

    /* Continue upload */
    uc cont_up_pa[]= {
        0x00, 0x01, 0x12, 0x04, 0x11, 0x3f, 0x08, 0x00
    };
    uc cont_up_da[]= {
        0xff, 0x09, 0x00, 0x02,
        /* Anzahl Telegramme die ohne ack angenommen werden = 20 */
        MAXUNACKED, 0x00
    };

    *length = 0;
    filename_len = strlen(filename);    /* max. 32 chars */
    if (filename_len > 32) {
        return -1;
    }
    req_up_da[3] = filename_len + 2;    /* + 1 Byte Anzahl Telegramme + 1 Byte unbekannt */
    memcpy(&req_up_da[6], filename, filename_len);

    p.header = dc->msgOut + dc->PDUstartO;
    _daveInitPDUheader(&p, 7);
    _daveAddParam(&p, req_up_pa, sizeof(req_up_pa));
    _daveAddData(&p, req_up_da, 6 + filename_len);

    res = _daveExchange(dc, &p);
    if (res != daveResOK) {
        return res;
    }
    res = _daveSetupReceivedPDU(dc, &p2);
    /* Errorcode im Parameterteil prüfen */
    res = daveGetU16from(&p2.param[10]);
    LOG2("daveGetNCfile: Response start upload, param.errorcode=0x%04x\n", res);
    if (res != 0) {
        return -2;
    }
    cont_up_pa[7] = p2.param[7];      /* Sequenznummer für alle folgenden Continue-Uploads verwenden */
    LOG2("daveGetNCfile: Verwendete Sequenznummer=%d\n", cont_up_pa[7]);
    res = _daveTestResultData(&p2);
    if (res != daveResOK) {
        return res;
    }
    LOG2("daveGetNCfile: Response start upload, p2.udlen=%d\n", p2.udlen);
    /* Vor den eigentlichen Daten sind hier noch 2 Bytes unbekannter Funktion eingeschoben */
    part_len = p2.udlen - 2;
    if (part_len <= 0) {
        return -3;
    }
    memcpy(buffer + tot_len, p2.data + 6, part_len);
    tot_len += part_len;
    /* Wenn ab hier noch nicht alles gelesen, dann werden bis zu 20 Telegramme gesendet die 
     * nicht bestätigt werden müssen. Dann gibt es ein ack usw. usf.
     */
    while (p2.param[9] != 0) {     /* 0 = Last data unit */
        LOG2("daveGetNCfile: unackcount=%d\n", unackcount);
        /* Nach 20 Telegrammen continue Telegramm senden */
        if (unackcount == MAXUNACKED) {
            LOG1("daveGetNCfile: Sende continue Telegramm\n");
            p.header = dc->msgOut + dc->PDUstartO;
            _daveInitPDUheader(&p, 7);
            _daveAddParam(&p, cont_up_pa, sizeof(cont_up_pa));
            _daveAddData(&p, cont_up_da, sizeof(cont_up_da));
            res = _daveSendTCP(dc, &p);
            if (res != daveResOK) {
                return res;
            }
            unackcount = 0;
        }
        LOG1("daveGetNCfile: Empfange Upload Push-Telegramm\n");
        res = _daveGetResponseISO_TCP(dc);
        if (res != daveResOK) {
            return res;
        }
        res = _daveSetupReceivedPDU(dc, &p2);
        /* Errorcode im Parameterteil prüfen */
        res = daveGetU16from(&p2.param[10]);
        LOG2("daveGetNCfile: continue upload, param.errorcode=0x%04x\n", res);
        if (res != 0) {
            return -4;
        }
        res = _daveTestResultData(&p2);
        if (res != daveResOK) {
            return res;
        }
        LOG2("daveGetNCfile: Response start upload, p2.udlen=%d\n", p2.udlen);
        part_len = p2.udlen - 2;
        if (part_len <= 0) {
            return -5;
        }
        memcpy(buffer + tot_len, p2.data + 6, part_len);
        tot_len += part_len;
        unackcount++;
    }
    *length = tot_len;
    return res;
}
```


----------



## Thomas_v2.1 (21 Oktober 2017)

Liegt hier vielleicht ein Netzwerkproblem vor?
In deinem Wireshark Log daveGetNcFile_BigUpload_Debug dauert es nämlich vom letzten Telegramm von der NC in #277 bis zum Continue in #3086 etwa 84 Sekunden. Beim zweiten Mal zwischen #3118 und #5785 sind es 82 Sekunden. Oder liegt es an den Debug-Ausgaben?


----------



## Jochen Kühner (21 Oktober 2017)

Muss ich auch was tun? 
Hans baust du das in libnodave ein?


----------



## Hans54216 (22 Oktober 2017)

Jochen Kühner schrieb:


> Muss ich auch was tun?
> Hans baust du das in libnodave ein?


Ich bau das wieder in libnodave und die dotNet Lib ein.


----------



## Hans54216 (22 Oktober 2017)

Thomas_v2.1 schrieb:


> Liegt hier vielleicht ein Netzwerkproblem vor?
> In deinem Wireshark Log daveGetNcFile_BigUpload_Debug dauert es nämlich vom letzten Telegramm von der NC in #277 bis zum Continue in #3086 etwa 84 Sekunden. Beim zweiten Mal zwischen #3118 und #5785 sind es 82 Sekunden. Oder liegt es an den Debug-Ausgaben?



Ich rufe die Methoden in meinen VS Testprojekt auf. Die Ausgabe erfolgt über die integrierte Ausgabe von VS. Die Ausgabe ist schon recht zäh. Hab schon gedacht, dass das gar nicht mehr aufhört.

Was meinst du mit "Pipe in eine Textdatei"?


----------



## Thomas_v2.1 (22 Oktober 2017)

In diesem Fall ist es keine Pipe sondern eine Ausgabeumleitung, mit der die Ausgaben auf stdout in eine Textdatei umgeleitet werden. Das geht meistens etwas schneller als die Ausgabe von stdout auf dem Bildschirm. Das funktioniert unter Windows mit dem Größer-Zeichen in einer Eingabeaufforderung. Beispiel:

testISO_TCP.exe 192.168.1.40 > dump.txt

Die Ausgaben landen dann in der Textdatei dump.txt

Die Pipe ist der vertikale Balken |. Damit kannst du stdout eines Programms mit stdin eines anderen verbinden. Verwendbar an beispielsweise in so einer Funktion:
netstat -ano | find ":102 " > ergebnis.txt

Die Ausgabe von netstat wird dann als Eingabe an find weitergeleitet, der darin nach ":102 " sucht und deren Ausgabe dann in die Textdatei ergebnis.txt ausgeben.


----------



## Hans54216 (22 Oktober 2017)

Ich bring die TestISO_TCP.exe nicht zum laufen. Wie muss ich den PI-Dienst starten?


```
uc param[2];
            param[0]= "P01";
            param[1]= "/_N_WKS_DIR/_N_TEST_JE_WPD/_N_TEST_UPLOAD2_MPF";
            printf("Start PI-Service...\n");
            res = davePIstart_nc(dc, "_N_F_XFER", &param, 2);
```


----------



## Thomas_v2.1 (22 Oktober 2017)

Das mit der testISO_TCP.exe war nur ein Beispiel. Das funktioniert mit jeder ausführbaren Datei die Ausgaben z.B. per printf an stdout ausgibt.


----------



## Hans54216 (22 Oktober 2017)

Gut zu wissen. Hab jetzt mit meine C# Anwendung den Dump erzeugt.

Fehler wieder -4.

Anhang anzeigen daveGetNcFile_BigUpload_Error3.rar


----------



## Thomas_v2.1 (22 Oktober 2017)

Aufruf der PI-Funktion war meine ich z.B. so:

```
const char *pistart_parameter[] = {
    "P01",
    "_N_MPF_DIR/_N_TEILEPROG2_MPF",
    ""
};

res = davePIstart_nc(dc, "_N_F_OPEN", pistart_parameter, 2);
```

Ich nutze das ja alles selber überhaupt nicht.


----------



## Thomas_v2.1 (22 Oktober 2017)

Da scheint etwas in der libnodave-Funktion readISOpacket() nicht ganz sauber zu sein:

daveGetNCfile: continue upload, param.errorcode=0x0000
daveGetNCfile: Response start upload, p2.udlen=934
daveGetNCfile: unackcount=11
daveGetNCfile: Empfange Upload Push-Telegramm
readISOpacket: 791 bytes read, 967 needed

daveGetNCfile: continue upload, param.errorcode=0x0000
daveGetNCfile: Response start upload, p2.udlen=934
daveGetNCfile: unackcount=12
daveGetNCfile: Empfange Upload Push-Telegramm
readISOpacket: 1460 bytes read, 12320 needed

readISOpacket() liest erst nur den TPKT Header, und versucht dann die dort angegebene Anzahl an Bytes zu lesen und diese zu verarbeiten. Jetzt scheint es so also ob es sein kann, dass wenn der Header schon im Puffer ist, aber die Daten noch nicht vollständig, einfach so versucht wird die nicht vollständigen Daten zu verarbeiten. Dann gibt es einen Versatz und danach bricht alles zusammen.

Entweder man versucht wenn die Anzahl nicht im Puffer ist, Zeit x zu warten und dann nochmal zu versuchen, oder schreibt das in einen Zwischenpuffer und setzt das dann mit dem nächsten Lesebefehl zusammen.
Ich hatte so einen ähnlichen Fehler auch bei mir in Nettoplcsim, TCP ist nämlich nicht immer so einfach wie man denkt.


----------



## Thomas_v2.1 (22 Oktober 2017)

Probier mal folgende Änderung an der _daveReadISOPacket. Die Änderungen von mir sind die mit "FIX"


```
int DECL2 _daveReadISOPacket(daveInterface * di,uc *b) {
	int res,i,length, follow;
    int remaining;  /* FIX */
	uc lhdr[7];
	i=_daveTimedRecv(di, b, 4);
	if (i<0) return 0;
	res=i;
        if (res<4) {
	    if (daveDebug & daveDebugByte) {
		LOG2("res %d ",res);
		_daveDump("readISOpacket: short packet", b, res);
	    }
	    return (0); /* short packet */
	}
	length=b[3]+0x100*b[2];
	i=_daveTimedRecv(di, b+4, length-4);
	res+=i;
	if (daveDebug & daveDebugByte) {
	    LOG3("readISOpacket: %d bytes read, %d needed\n",res, length);
	    _daveDump("readISOpacket: packet", b, res);
	}
    /* FIX START: Force to read the complete TPKT if first was not complete */
    remaining = length - res;
    while (remaining > 0)
        LOG2("readISOpacket: Trying to read %d remaining bytes of the complete TPKT\n", remaining);
        i = _daveTimedRecv(di, b+4 + res, remaining);
        if (i < 0) return 0;
        res += i;
        remaining = length - res;
    }
    /* FIX END */
	follow=((b[5]==0xf0)&& ((b[6] & 0x80)==0) );
	while (follow) {
	    if (daveDebug & daveDebugByte) {
		LOG2("readISOpacket: more data follows %d\n",b[6]);
	    }
	    i=_daveTimedRecv(di, lhdr, 7);
	    length=lhdr[3]+0x100*lhdr[2];
	    if (daveDebug & daveDebugByte) {
		_daveDump("readISOpacket: follow %d %d", lhdr, i);
	    }
	    i=_daveTimedRecv(di, b+res, length-7);
	    if (daveDebug & daveDebugByte) {
		_daveDump("readISOpacket: follow %d %d", b+res, i);
	    }
	    res+=i;
	    follow=((lhdr[5]==0xf0)&& ((lhdr[6] & 0x80)==0) );
	}
	return (res);
}
```


----------



## Hans54216 (22 Oktober 2017)

Der Upload ist mal durchgelaufen. Beim zusammensetzen der Doppelten Telegramme werden noch Bytes verworfen. (Sieht so aus als ob 4 Chars fehlen)

Anhang anzeigen daveGetNcFile_BigUpload_Error4.rar


----------



## Thomas_v2.1 (22 Oktober 2017)

Nimm mal bei die 4 raus, die wird natürlich oben schon draufgerechnet. Von:
i = _daveTimedRecv(di, b+4 + res, remaining);
in:
i = _daveTimedRecv(di, b + res, remaining);


----------



## Hans54216 (22 Oktober 2017)

Sieht gut aus. Muss schauen wann ich wieder an die "Problemmaschine" komme und ob es dort auch funktioniert.

Danke!


----------



## Thomas_v2.1 (22 Oktober 2017)

Bei Verarbeiten der ggf. fragmentierten ISO Pakete nach while(follow) ist der Fehler auch noch vorhanden. Das sollte noch mal komplett überarbeitet werden.


----------



## Jochen Kühner (23 Oktober 2017)

sollten wir vlt. mal an zottel schreiben das da noch ein problem besteht.


----------



## Thomas_v2.1 (23 Oktober 2017)

Jochen Kühner schrieb:


> sollten wir vlt. mal an zottel schreiben das da noch ein problem besteht.



Wird das von Zottel überhaupt noch gepflegt?

Bei einer S7 wird das Problem auch nie in Erscheinung treten, da libnodave bei Verbindungsaufbau angibt, dass es nur ein Telegramm ohne Bestätigung sendet und empfangen kann. Und selbst die unwahrscheinliche 960er PDU passt dann immer in eine Ethernet MTU von z.B. 1472 Bytes.
Das fällt bei der NC eben auf, weil diese erstens 960 Bytes PDU unterstützt, und dann auch noch hier bis zu 20 Telegramme direkt hintereinander schickt ohne auf Bestätigung zu warten. Und dann wird gelegentlich eine PDU in zwei TCP Telegramme getrennt übertragen und dann von der TCP-Schicht anschließend wieder passend zusammengesetzt.
Nichtsdestotrotz ist es natürlich trotzdem nicht richtig es so zu machen.


----------



## Jochen Kühner (23 Oktober 2017)

Thomas_v2.1 schrieb:


> Wird das von Zottel überhaupt noch gepflegt?
> 
> Bei einer S7 wird das Problem auch nie in Erscheinung treten, da libnodave bei Verbindungsaufbau angibt, dass es nur ein Telegramm ohne Bestätigung sendet und empfangen kann. Und selbst die unwahrscheinliche 960er PDU passt dann immer in eine Ethernet MTU von z.B. 1472 Bytes.
> Das fällt bei der NC eben auf, weil diese erstens 960 Bytes PDU unterstützt, und dann auch noch hier bis zu 20 Telegramme direkt hintereinander schickt ohne auf Bestätigung zu warten. Und dann wird gelegentlich eine PDU in zwei TCP Telegramme getrennt übertragen und dann von der TCP-Schicht anschließend wieder passend zusammengesetzt.
> Nichtsdestotrotz ist es natürlich trotzdem nicht richtig es so zu machen.



Aber auch sonstige Netzwerk Hardware kann ja Telegramme aufteilen...
https://serverfault.com/questions/534063/can-tcp-and-udp-packets-be-split-into-pieces


----------



## Hans54216 (17 November 2017)

Ich hab gerade versucht einen Ordner mit allen Unterordnern zu lesen. Dabei kommt es zum Crash in NoDave und das Programm ist zu. Es kann/wird auch kein Dump geschrieben.

Das lesen des Bereiches hat noch funktioniert "/_N_WKS_DIR" (Bereich Werkstücke). Anschließend soll der Ordner in diesem Bereich gelesen werden "_N_G_GQ_TEST_SWITCH_VCS_WPD" (WPD-> Ordner)

Anhang anzeigen FolderUpload.rar


----------



## Hans54216 (17 November 2017)

Hier noch ein WireShark Log zunächst mit der "Alten" Methode "UploadFromNC" und danach mit der "neuen" "UploadNcFile". Die alte funktioniert und die neue nicht.

Anhang anzeigen FolderUpload2.rar


----------



## Thomas_v2.1 (17 November 2017)

Das heißt, der Upload hat bei den anderen Dateien funktioniert?

Was ich auf den ersten Blick sehe ist, dass die NC trotz gesetzem "Last Data Unit" flag das gleiche Telegramm nochmal sendet, aber dann sollte eigentlich nichts abstürzen.

Probier mal den debug Level zu erhöhen und dann gucken wie weit man dort noch Ausgaben eingefangen bekommt.


----------



## Hans54216 (18 November 2017)

```
_daveExchange PDU number: 65537
ReadFromNck enter _daveExchangeTCP
send packet: : 
                            0:0x03,0x00,0x00,0x3A,0x02,0xF0,0x80,0x32,0x07,0x00,0x00,0x00,0x01,0x00,0x08,0x00,
                            10:0x21,0x00,0x01,0x12,0x04,0x11,0x7F,0x06,0x00,0xFF,0x09,0x00,0x1D,0x14,0x00,0x5F,
                            20:0x4E,0x5F,0x47,0x5F,0x47,0x51,0x5F,0x54,0x45,0x53,0x54,0x5F,0x53,0x57,0x49,0x54,
                            30:0x43,0x48,0x5F,0x56,0x43,0x53,0x5F,0x57,0x50,0x44,
readISOpacket: 165 bytes read, 165 needed
readISOpacket: packet: 
                            0:0x03,0x00,0x00,0xA5,0x02,0xF0,0x80,0x32,0x07,0x00,0x00,0x00,0x01,0x00,0x0C,0x00,
                            10:0x88,0x00,0x01,0x12,0x08,0x12,0xBF,0x06,0x63,0x01,0x00,0x00,0x00,0xFF,0x09,0x00,
                            20:0x84,0x00,0xFB,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x31,0x37,0x31,0x31,0x31,
                            30:0x35,0x31,0x30,0x32,0x37,0x35,0x36,0x20,0x20,0x20,0x20,0x3B,0x24,0x50,0x41,0x54,
                            40:0x48,0x3D,0x2F,0x5F,0x4E,0x5F,0x77,0x6B,0x73,0x5F,0x64,0x69,0x72,0x2F,0x5F,0x4E,
                            50:0x5F,0x47,0x5F,0x47,0x51,0x5F,0x54,0x45,0x53,0x54,0x5F,0x53,0x57,0x49,0x54,0x43,
                            60:0x48,0x5F,0x56,0x43,0x53,0x5F,0x57,0x50,0x44,0x0A,0x30,0x30,0x30,0x30,0x37,0x33,
                            70:0x36,0x39,0x31,0x37,0x31,0x31,0x31,0x35,0x31,0x30,0x32,0x37,0x35,0x35,0x20,0x20,
                            80:0x20,0x20,0x20,0x37,0x37,0x37,0x37,0x37,0x20,0x5F,0x4E,0x5F,0x47,0x5F,0x47,0x51,
                            90:0x5F,0x54,0x45,0x53,0x54,0x5F,0x53,0x57,0x49,0x54,0x43,0x48,0x5F,0x56,0x43,0x53,
                            a0:0x5F,0x4D,0x50,0x46,0x0A,
ReadFromNck _daveExchangeTCP res from read 165
result of exchange: 0
PDU header: 
                            0:0x32,0x07,0x00,0x00,0x00,0x01,0x00,0x0C,0x00,0x88,
plen: 12 dlen: 136
Parameter: 
                            0:0x00,0x01,0x12,0x08,0x12,0xBF,0x06,0x63,0x01,0x00,0x00,0x00,
Data     : 
                            0:0xFF,0x09,0x00,0x84,0x00,0xFB,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x31,0x37,
                            10:0x31,0x31,0x31,0x35,0x31,0x30,0x32,0x37,0x35,0x36,0x20,0x20,0x20,0x20,0x3B,0x24,
                            20:0x50,0x41,0x54,0x48,0x3D,0x2F,0x5F,0x4E,0x5F,0x77,0x6B,0x73,0x5F,0x64,0x69,0x72,
                            30:0x2F,0x5F,0x4E,0x5F,0x47,0x5F,0x47,0x51,0x5F,0x54,0x45,0x53,0x54,0x5F,0x53,0x57,
                            40:0x49,0x54,0x43,0x48,0x5F,0x56,0x43,0x53,0x5F,0x57,0x50,0x44,0x0A,0x30,0x30,0x30,
                            50:0x30,0x37,0x33,0x36,0x39,0x31,0x37,0x31,0x31,0x31,0x35,0x31,0x30,0x32,0x37,0x35,
                            60:0x35,0x20,0x20,0x20,0x20,0x20,0x37,0x37,0x37,0x37,0x37,0x20,0x5F,0x4E,0x5F,0x47,
                            70:0x5F,0x47,0x51,0x5F,0x54,0x45,0x53,0x54,0x5F,0x53,0x57,0x49,0x54,0x43,0x48,0x5F,
                            80:0x56,0x43,0x53,0x5F,0x4D,0x50,0x46,0x0A,
daveGetNCfile: Response start upload, param.errorcode=0x0000
daveGetNCfile: Verwendete Sequenznummer=99
daveGetNCfile: Response start upload, p2.udlen=132
```

Anhang anzeigen FolderUpload3.rar


----------



## Hans54216 (18 November 2017)

Thomas_v2.1 schrieb:


> Das heißt, der Upload hat bei den anderen Dateien funktioniert?



Der Upload des Verzeichnisses hat mit der alten sowie der nen Methode funktioniert. Der Upload von Dateien funktioniert auch.
Der Upload von Ordnern funktioniert mit der Neuen jedoch nicht mehr.

Beim Upload von Verzeichnissen oder Ordnern werden nicht die ganzen Dateien, sondern deren Name + Zeitstempel gesendet.


----------



## Thomas_v2.1 (18 November 2017)

Die Ausgaben sind so wie sie auch sein müssten. Nach der letzten Ausgabe werden noch die Daten in den buffer umkopiert und dann wird die Funktion beendet, weil die eine Antwort schon die Last Data unit ist.

Kannst du in deinem eigenen Programm noch eine Ausgabe nach dem Aufruf von daveGetNCfile einbauen, mit Ausgabe des Rückgabewertes? Oder in daveGetNCfile vor dem return noch eine, z.B. den buffer dumpen.

Ich weiß nur nicht warum deine NC das gleiche Telegramm zwei mal sendet, aber das dürfte eigentlich nicht stören weil die Funktion dieses gar nicht mehr zu Gesicht bekommt.


----------



## Thomas_v2.1 (18 November 2017)

Also z.B. in der dateGetNCfile:

LOG2("daveGetNCfile: tot_len=%d\n", tot_len);
return res;


----------



## Hans54216 (18 November 2017)

Thomas_v2.1 schrieb:


> Ich weiß nur nicht warum deine NC das gleiche Telegramm zwei mal sendet, aber das dürfte eigentlich nicht stören weil die Funktion dieses gar nicht mehr zu Gesicht bekommt.



Was meinst du mit zwei mal das gleiche Telegramm?




Rückgabewert scheint noch zu passen.

Wenn ich im Debugger das ganze bis zum Absturz verfolge komme ich direkt beim Rückgabewert der NoDave Methode an. Da hilft auch kein Try Catch


```
public int daveGetNcFile(string filename, byte[] buffer, ref int length)
{
    if (IntPtr.Size == 8)
        return daveGetNcFile64(pointer, filename, buffer, ref length);
    else
        return daveGetNcFile32(pointer, filename, buffer, ref length);
}


protected static extern int daveGetNcFile64(IntPtr dc, string filename, byte[] buffer, ref int length);
```



```
_daveExchange PDU number: 65537
ReadFromNck enter _daveExchangeTCP
send packet: : 
                            0:0x03,0x00,0x00,0x3A,0x02,0xF0,0x80,0x32,0x07,0x00,0x00,0x00,0x01,0x00,0x08,0x00,
                            10:0x21,0x00,0x01,0x12,0x04,0x11,0x7F,0x06,0x00,0xFF,0x09,0x00,0x1D,0x14,0x00,0x5F,
                            20:0x4E,0x5F,0x47,0x5F,0x47,0x51,0x5F,0x54,0x45,0x53,0x54,0x5F,0x53,0x57,0x49,0x54,
                            30:0x43,0x48,0x5F,0x56,0x43,0x53,0x5F,0x57,0x50,0x44,
readISOpacket: 165 bytes read, 165 needed
readISOpacket: packet: 
                            0:0x03,0x00,0x00,0xA5,0x02,0xF0,0x80,0x32,0x07,0x00,0x00,0x00,0x01,0x00,0x0C,0x00,
                            10:0x88,0x00,0x01,0x12,0x08,0x12,0xBF,0x06,0xBE,0x01,0x00,0x00,0x00,0xFF,0x09,0x00,
                            20:0x84,0x00,0xFB,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x31,0x37,0x31,0x31,0x31,
                            30:0x35,0x31,0x30,0x32,0x37,0x35,0x36,0x20,0x20,0x20,0x20,0x3B,0x24,0x50,0x41,0x54,
                            40:0x48,0x3D,0x2F,0x5F,0x4E,0x5F,0x77,0x6B,0x73,0x5F,0x64,0x69,0x72,0x2F,0x5F,0x4E,
                            50:0x5F,0x47,0x5F,0x47,0x51,0x5F,0x54,0x45,0x53,0x54,0x5F,0x53,0x57,0x49,0x54,0x43,
                            60:0x48,0x5F,0x56,0x43,0x53,0x5F,0x57,0x50,0x44,0x0A,0x30,0x30,0x30,0x30,0x37,0x33,
                            70:0x36,0x39,0x31,0x37,0x31,0x31,0x31,0x35,0x31,0x30,0x32,0x37,0x35,0x35,0x20,0x20,
                            80:0x20,0x20,0x20,0x37,0x37,0x37,0x37,0x37,0x20,0x5F,0x4E,0x5F,0x47,0x5F,0x47,0x51,
                            90:0x5F,0x54,0x45,0x53,0x54,0x5F,0x53,0x57,0x49,0x54,0x43,0x48,0x5F,0x56,0x43,0x53,
                            a0:0x5F,0x4D,0x50,0x46,0x0A,
ReadFromNck _daveExchangeTCP res from read 165
result of exchange: 0
PDU header: 
                            0:0x32,0x07,0x00,0x00,0x00,0x01,0x00,0x0C,0x00,0x88,
plen: 12 dlen: 136
Parameter: 
                            0:0x00,0x01,0x12,0x08,0x12,0xBF,0x06,0xBE,0x01,0x00,0x00,0x00,
Data     : 
                            0:0xFF,0x09,0x00,0x84,0x00,0xFB,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x31,0x37,
                            10:0x31,0x31,0x31,0x35,0x31,0x30,0x32,0x37,0x35,0x36,0x20,0x20,0x20,0x20,0x3B,0x24,
                            20:0x50,0x41,0x54,0x48,0x3D,0x2F,0x5F,0x4E,0x5F,0x77,0x6B,0x73,0x5F,0x64,0x69,0x72,
                            30:0x2F,0x5F,0x4E,0x5F,0x47,0x5F,0x47,0x51,0x5F,0x54,0x45,0x53,0x54,0x5F,0x53,0x57,
                            40:0x49,0x54,0x43,0x48,0x5F,0x56,0x43,0x53,0x5F,0x57,0x50,0x44,0x0A,0x30,0x30,0x30,
                            50:0x30,0x37,0x33,0x36,0x39,0x31,0x37,0x31,0x31,0x31,0x35,0x31,0x30,0x32,0x37,0x35,
                            60:0x35,0x20,0x20,0x20,0x20,0x20,0x37,0x37,0x37,0x37,0x37,0x20,0x5F,0x4E,0x5F,0x47,
                            70:0x5F,0x47,0x51,0x5F,0x54,0x45,0x53,0x54,0x5F,0x53,0x57,0x49,0x54,0x43,0x48,0x5F,
                            80:0x56,0x43,0x53,0x5F,0x4D,0x50,0x46,0x0A,
daveGetNcFile: Response start upload, param.errorcode=0x0000
daveGetNcFile: Verwendete Sequenznummer=190
daveGetNcFile: Response start upload, p2.udlen=132
daveGetNcFile: tot_len=130
```


----------



## Thomas_v2.1 (18 November 2017)

Hans54216 schrieb:


> Was meinst du mit zwei mal das gleiche Telegramm?



Das nicht gezeigte Telegramm #52 ist identisch zu #51.

Hast du eine Möglichkeit die Aufrufe direkt aus einem C-Programm heraus zu testen?

Mit dem C#-Wrapper kenne ich mich nicht aus. Woher stammen z.B. daveGetNcFile32 und daveGetNcFile64?


----------



## Hans54216 (18 November 2017)

Thomas_v2.1 schrieb:


> Hast du eine Möglichkeit die Aufrufe direkt aus einem C-Programm heraus zu testen?



Muss ich schauen ob ich das zum laufen bekomme.



Thomas_v2.1 schrieb:


> Mit dem C#-Wrapper kenne ich mich nicht aus. Woher stammen z.B. daveGetNcFile32 und daveGetNcFile64?




```
[DllImport("libnodave_jfkmod.dll", EntryPoint = "daveGetNcFile")]
protected static extern int daveGetNcFile32(IntPtr dc, string filename, byte[] buffer, ref int length);

[DllImport("libnodave_jfkmod64.dll", EntryPoint = "daveGetNcFile")]
protected static extern int daveGetNcFile64(IntPtr dc, string filename, byte[] buffer, ref int length);
```

Die NoDave ist als 32 und als 64 Bit Version compiliert. Mit den beiden Methoden daveGetNcFile32 und daveGetNcFile64 wird die Methode in der richtigen dll aufgerufen.


----------



## Hans54216 (18 November 2017)

Ich bring die TestISO_TCP nicht zum laufen.

Programm hängt sich schon beim Ausführen des "res = davePIstart_nc(dc, "_N_F_XFER", &param, 2);" auf.

Anhang anzeigen libnodave_20171118.rar


----------



## Thomas_v2.1 (18 November 2017)

param ist bei dir ein Array für 3 unsigned char Werte. Das muss aber ein Array für (mindestens) 2 Zeiger auf ein char array sein.
also anstatt:

uc param[3];

dann:
uc* param[3];

Oder so:

```
const char *pistart_parameter[] = {
    "P01",
    "/_N_wks_dir/_N_G_GQ_TEST_SWITCH_VCS_WPD",
    ""
};
```


----------



## Hans54216 (18 November 2017)

Der PI-Dienst funktioniert, jedoch kommt von der NC ein Fehler.

Die Methode daveGetNcFile wird gestartet, führt jedoch ebenfalls zum Absturz des Programms.

Anhang anzeigen FolderUpload4.rar


----------



## Hans54216 (18 November 2017)

Ich hab auch nochmal den Test gemacht, wenn ich zunächst das Verzeichnis und anschließend den Ordner lade.

Laden des Verzeichnisses führt zu keinem Crash, jedoch das laden des Ordners. (Wegen fehlgeschlagenem PI-Dienst schickt die NC keine Daten für den Upload)


```
uc* param[10];
            int length;
            printf("daveSetDebug: 0x1ffff\n");
            daveSetDebug(0x1ffff);


            //############# Upload DIR #########
            printf("Init PI-Service...\n");            
            param[0]= "P01";
            param[1]= "/_N_wks_dir";
            printf("Start PI-Service \"DIR\"...\n");
			res = davePIstart_nc(dc, "_N_F_XFER", &param, 2);
            printf("davePIstart_nc res=%d\n", res);


            //Upload DIR von NC
            printf("Starte daveGetNcFile...\n");
            res = daveGetNcFile(dc, "_N_wks_dir", buffer, &length);
            //######################

            //############ Upload Folder ##########
            //PI-Service
            printf("Init PI-Service...\n");
            
            param[0]= "P01";
            param[1]= "/_N_wks_dir/_N_G_GQ_TEST_SWITCH_VCS_WPD";
            printf("Start PI-Service...\n");


            res = davePIstart_nc(dc, "_N_F_XFER", &param, 2);
            printf("davePIstart_nc res=%d\n", res);
            


            //Upload von NC
            printf("Starte daveGetNcFile...\n");
            res = daveGetNcFile(dc, "_N_G_GQ_TEST_SWITCH_VCS_WPD", buffer, &length);
            printf("daveGetNcFile res=%d\n", res);
            //######################
```

Anhang anzeigen FolderUpload5.rar


----------



## Thomas_v2.1 (18 November 2017)

Du verwendest eine andere Slot-Nummer als in den anderen Aufzeichnungen, vermutlich ist das die SPS und nicht NC.

Übergibst du in daveGetNCfile für length auch die Adresse einer int Variable?
Ich kann es mir nicht erklären, vor allem wenn du sagst dass die Funktion beim Upload von Dateien funktioniert. Ich sehe in den Aufzeichnungen überhaupt keinen Unterschied, bis auf die doppelten Antworten.


----------



## Hans54216 (18 November 2017)

Wie muss ich den Slot an die TestISO übergeben? --slot=4


----------



## Thomas_v2.1 (18 November 2017)

Hans54216 schrieb:


> Wie muss ich den Slot an die TestISO übergeben? --slot=4



Ja, aber vor der IP-Adresse. In deinen Aufzeichnungen wird slot = 2 verwendet, das ist default wenn kein Parameter angegeben wurde.


----------



## Hans54216 (18 November 2017)

Jetzt funktioniert auch der PI-Service und die NC schickt auch die Daten.

Verhalten mit dem Absturz ist jedoch noch gleich. Spielt also keine Rolle ob die Methode per C# oder per C aufgerufen wird.

Anhang anzeigen FolderUpload6.rar


----------



## Thomas_v2.1 (18 November 2017)

Hab den (oder zumindest einen) Fehler gefunden.


```
uc req_up_da[]= {
        0xff, 0x09, 0x00, 32,
        /* Anzahl Telegramme die ohne ack angenommen werden = 20  */
        MAXUNACKED, 0x00,
        /* Dateiname max. 32 Zeichen */
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00
    };
```
muss in


```
uc req_up_da[]= {
        0xff, 0x09, 0x00, 32,
        /* Anzahl Telegramme die ohne ack angenommen werden = 20  */
        MAXUNACKED, 0x00,
        /* Dateiname max. 32 Zeichen */
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00
    };
```
geändert werden.

Ich hatte also nur 22 und nicht 32 Zeichen für den Dateinamen vorgesehen. Bei längeren Dateinamen als 22 wird dann anderer Speicher überschrieben.


----------



## Hans54216 (18 November 2017)

Kommt jetzt nicht mehr zum Absturz. (Upload hat ja eigentlich eh schon funktioniert)

Ich test jetzt noch ein bisschen, sieht aber schon mal gut aus.
Danke!


----------



## Thomas_v2.1 (18 November 2017)

Ich überlege gerade wie ich auf die maximal 32 Zeichen komme. Weißt du ob es da im Dateisystem eine Beschränkung gibt?

Der Fehler ist deiner nodave.c auch noch in anderen Funktionen für die NC vorhanden. Einfach mal nach "32 Zeichen" suchen.


----------



## Hans54216 (18 November 2017)

Ich denk die Kommen von mir.

Maximale Länge für Dateinamen ist   24
NC Syntax _N_                                  3
Extension _SPF, _MPF, _DIR, _WPD    4
\0                                                    1

24+3+4+1 -> 32


----------



## Hans54216 (7 April 2018)

Ich bekomme nen Fehler von der LibNoDave beim lesen eines Drive Parameters und es sieht so aus, dass der WireShark Filter das selbe Problem hat.





Anhang anzeigen p0400.rar


----------



## Thomas_v2.1 (7 April 2018)

Das ist seltsam.
Bei einer S7 ist bei Transport Size 5=INTEGER die Längenangabe in Bits. D.h. wenn ein INTEGER übertragen wird, dann steht im Längenfeld 0x10. WinCC flexible fragt meistens mit der dem Datentyp der Variable zugehörigen Transportgröße.


----------



## Thomas_v2.1 (7 April 2018)

Zur Sicherheit gerade nochmal einen Test an einer Et200S CPU gemacht.
Wenn ich ein Array aus zwei Integern lese, dann antwortet die SPS mit Länge 0x0020 = 32 / 4 = 8 Bytes. D.h. so wie es mein Wireshark Filter und auch libnodave erwarten.

Mir fällt auch gerade nichts ein wie ich da eine Sonderbehandlung einbauen könnte. Das lässt sich nirgends erkennen, dass da anscheinend auf einmal auf die Byteanzahl gewechselt wurde.


----------



## Hans54216 (7 April 2018)

Das ist die Methode in NoDave mit dem zugehörigen Dump. (Wenn ich hart die len=2 schreibe funktioniert es.)


```
/*
Execute a predefined read request. Store results into the resultSet structure.
*/
int DECL2 daveExecReadRequest(daveConnection * dc, PDU *p, daveResultSet* rl){
    PDU p2;
    uc * q;
    daveResult * cr, *c2;
    int res, i, len, rlen;
   if (daveDebug & daveDebugPDU)
   {
      LOG4("daveExecReadRequest(dc:%p, PDU:%p, rl:%p\n", dc, p, rl);
      FLUSH;    
   }
    dc->AnswLen=0;    // 03/12/05
    dc->resultPointer=NULL;
    dc->_resultPointer=NULL;
    res=_daveExchange(dc, p);
    if (res!=daveResOK) return res;
    res=_daveSetupReceivedPDU(dc, &p2);
    if (res!=daveResOK) return res;
    res=_daveTestReadResultMulti(&p2);
    if (res!=daveResOK) return res;
    i=0;
    if (rl!=NULL) {
        cr=(daveResult*)calloc(p2.param[1], sizeof(daveResult));
        rl->numResults=p2.param[1];
        rl->results=cr;
        c2=cr;
        q=p2.data;
        rlen=p2.dlen;
        while (i<p2.param[1]) {
            /*        printf("result %d: %d  %d %d %d\n",i, *q,q[1],q[2],q[3]); */
         if (daveDebug & daveDebugPDU)
         {
            LOG2("daveExecReadRequest result %d: %d  %d %d %d\n",i, *q,q[1],q[2],q[3]);
            FLUSH;
         }
            if ((*q==255)&&(rlen>4)) {
                len=q[2]*0x100+q[3];
                if (q[1]==4) {
                    len>>=3;    /* len is in bits, adjust */
                } else if (q[1]==5) {            /* Fehlenden Size-Type INTEGER ergänzt */
                    len>>=3;    /* len is in bits, adjust */
                } else if (q[1]==7) {            /* Fehlenden Size-Type REAL ergänzt */
                     /* len is already in bytes, ok */
                } else if (q[1]==9) {
                    /* len is already in bytes, ok */
                } else if (q[1]==3) {
                    /* len is in bits, but there is a byte per result bit, ok */
                } else if (q[1]==6) {
                    /* integer access, len is in bytes */
                } else {
                    if (daveDebug & daveDebugPDU)
                        LOG2("fixme: what to do with data type %d?\n",q[1]);
                }
            } else {
                len=0;
            }
            /*        printf("Store result %d length:%d\n", i, len); */
         if (daveDebug & daveDebugPDU)
         {
            LOG2("Store result %d length:%d\n", i, len);
            FLUSH;
            //len=2;
         }
            c2->length=len;
            if(len>0){
                c2->bytes=(uc*)malloc(len);
                memcpy(c2->bytes, q+4, len);
            }
            c2->error=daveUnknownError;


            if (q[0]==0xFF) {
                c2->error=daveResOK;    
            } else
                c2->error=q[0];    


            /*        printf("Error %d\n", c2->error); */
            q+=len+4;
            rlen-=len;
            if ((len % 2)==1) {
                q++;
                rlen--;
            }
            c2++;
            i++;
        }
    }
    return res;
}
```


```
Dump
PDU header: 
                            0:0x32,0x01,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x00,
plen: 12 dlen: 0
Parameter: 
                            0:0x04,0x01,0x12,0x08,0x82,0xA1,0x01,0x90,0x00,0x01,0x1A,0x01,
daveExecReadRequest(dc:000000001A6DA810, PDU:000000001A6D6DF0, rl:000000001A6A3560
_daveExchange PDU number: 65536
ReadFromNck enter _daveExchangeTCP
send packet: : 
                            0:0x03,0x00,0x00,0x1D,0x02,0xF0,0x80,0x32,0x01,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,
                            10:0x00,0x04,0x01,0x12,0x08,0x82,0xA1,0x01,0x90,0x00,0x01,0x1A,0x01,
readISOpacket: 27 bytes read, 27 needed
readISOpacket: packet: 
                            0:0x03,0x00,0x00,0x1B,0x02,0xF0,0x80,0x32,0x03,0x00,0x00,0x00,0x00,0x00,0x02,0x00,
                            10:0x06,0x00,0x00,0x04,0x01,0xFF,0x05,0x00,0x02,0x00,0xF4,
ReadFromNck _daveExchangeTCP res from read 27
result of exchange: 0
PDU header: 
                            0:0x32,0x03,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x06,0x00,0x00,
plen: 2 dlen: 6
Parameter: 
                            0:0x04,0x01,
Data     : 
                            0:0xFF,0x05,0x00,0x02,0x00,0xF4,
Data hdr : 
                            0:0xFF,0x05,0x00,0x02,
Data     : 
                            0:0x00,0xF4,
error: ok
dave test result: p-param[0]: 4
daveExecReadRequest result 0: 0  443168096 65537 4079216
Store result 0 length:-348275808
daveUseResult(dc:000000001A6DA810, result set:000000001A6A3560, number:0)
result set has 1 results
result error: 0
result length: 0
```


----------



## Thomas_v2.1 (7 April 2018)

Wenn dann müsste bei der Abfrage sizetype=5 die Division durch 8 entfallen, weil die Länge bereits in der Anzahl an Bytes ist.

```
} else if (q[1]==5) {            /* Fehlenden Size-Type INTEGER ergänzt */
  /* only for NC: len is already in bytes, ok */
}
```

Aber dann funktioniert das an einer S7 nicht mehr.

Ich habe mir noch mal ein paar Aufzeichnungen angesehen. Bei anderen NC-Logfiles die ich so habe war das Verhalten auch schon so.
Diverse S7-SPS machen es aber anders. Wer von beiden das "richtig" im Sinne der vermutlichen Siemens Spezifikation macht, weiß ich nicht.
Wäre mal interessant was WinCC flexible macht wenn es ein NC-Bereich liest. Wenn das funktioniert, dann müsste dort eine Unterscheidung stattfinden. D.h. wird ein NC Bereich angefragt dann ist tsize in Bytes, sonst in Bits.


----------



## Hans54216 (7 April 2018)

Bei dem Bereich handelt es sich um den Antrieb (Sinamics). Bis jetzt hab ich nur Real Variablen vom Antrieb gelesen. Diese funktionieren.

Anhang anzeigen p0400_r0035.rar


----------



## Hans54216 (7 April 2018)

Die Methode "_daveDumpPDU" scheint es ja richtig zu machen.


```
PDU header: 
                            0:0x32,0x03,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x0E,0x00,0x00,
plen: 2 dlen: 14
Parameter: 
                            0:0x04,0x02,
Data     : 
                            0:0xFF,0x05,0x00,0x02,0x00,0xF4,0xFF,0x07,0x00,0x04,0x41,0x9B,0x33,0x30,
Data hdr : 
                            0:0xFF,0x05,0x00,0x02,
Data     : 
                            0:0x00,0xF4,
Data hdr : 
                            0:0xFF,0x07,0x00,0x04,
Data     : 
                            0:0x41,0x9B,0x33,0x30,
error: ok
```


```
/*
Hex dump PDU:
*/
void DECL2 _daveDumpPDU(PDU * p) {
    int i,dl;
    uc * pd;
    _daveDump("PDU header", p->header, p->hlen);
    LOG3("plen: %d dlen: %d\n",p->plen, p->dlen);
    if(p->plen>0) _daveDump("Parameter",p->param,p->plen);
    if(p->dlen>0) _daveDump("Data     ",p->data,p->dlen);
    if ((p->plen==2)&&(p->param[0]==daveFuncRead)) {
        pd=p->data;
        for (i=0;i<p->param[1];i++) {
            _daveDump("Data hdr ",pd,4);


            dl=0x100*pd[2]+pd[3];
            if (pd[1]==4) dl/=8;
            pd+=4;        
            _daveDump("Data     ",pd,dl);
            if(i<p->param[1]-1) dl=dl+(dl%2);      // the PLC places extra bytes at the end of all 
            // but last result, if length is not a multiple 
            // of 2
            pd+=dl;
        }
    } else if ((p->header[1]==1)&&/*(p->plen==2)&&*/(p->param[0]==daveFuncWrite)) {
        pd=p->data;
        for (i=0;i<p->param[1];i++) {
            _daveDump("Write Data hdr ",pd,4);


            dl=0x100*pd[2]+pd[3];
            if (pd[1]==4) dl/=8;
            pd+=4;        
            _daveDump("Data     ",pd,dl);
            if(i<p->param[1]-1) dl=dl+(dl%2);      // the PLC places extra bytes at the end of all 
            // but last result, if length is not a multiple 
            // of 2
            pd+=dl;
        }
    } else {    
        /*    
        if(p->dlen>0) {
        if(p->udlen==0)
        _daveDump("Data     ",p->data,p->dlen);
        else
        _daveDump("Data hdr ",p->data,4);
        }    
        if(p->udlen>0) _daveDump("result Data ",p->udata,p->udlen);
        */    
    }
    if ((p->header[1]==2)||(p->header[1]==3)) {
        LOG2("error: %s\n",daveStrerror(daveGetPDUerror(p)));
    }    
}
```


----------



## Thomas_v2.1 (7 April 2018)

libnodave kannte die anderen Transportgrößen 5 und 7 überhaupt nicht, vermutlich haben wir das irgendwann mal ergänzt aber nicht bei der dump-Funktion?
Bei einer S7 SPS braucht libnodave diese auch nicht zu kennen, weil wenn du bei der Anfrage angibst du möchtest 2 Bytes lesen, dann kommt auch niemals die Transportgröße 5 oder 7 zurück, sondern die SPS schickt dir auch Transportgröße Byte (dann ist die Anzahl in Bits). Frag mich nicht warum Siemens das überhaupt so vorgesehen hat.

Festzustellen ist, dass wenn du einen NC Bereich anfragst, die Transportgröße 5 anders zu interpretieren ist als bei einer S7-SPS. Bei Siemens muss man einiges einfach so hinnehmen wie es ist.


----------



## Hans54216 (7 April 2018)

Hab mal alle bekannten Datentypen des Antriebs ausgelesen.


```
V1_M_p04001_INT                              Error (3): this result contains no data
                                                                       AnzVar 1; akVar 0
                                                                       readsizes 2
                                                                       usedShortRequest False
V1_M_r0035_REAL                              19,8
V1_M_p00051_WORD                        2
V1_M_p0015_DWORD                       0
V1_M_p0161_CHAR                            0
V1_M_p9802_DINT                             Error (3): this result contains no data
                                                                       AnzVar 1; akVar 0
                                                                       readsizes 4
                                                                       usedShortRequest False
```

Anhang anzeigen Drive-Int_Real_Word_DWord_Char-DInt.rar



```
PDU header: 
                            0:0x32,0x01,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x00,
plen: 12 dlen: 0
Parameter: 
                            0:0x04,0x01,0x12,0x08,0x82,0xA1,0x01,0x90,0x00,0x01,0x1A,0x01,
PDU header: 
                            0:0x32,0x01,0x00,0x00,0x00,0x00,0x00,0x16,0x00,0x00,
plen: 22 dlen: 0
Parameter: 
                            0:0x04,0x02,0x12,0x08,0x82,0xA1,0x01,0x90,0x00,0x01,0x1A,0x01,0x12,0x08,0x82,0xA1,
                            10:0x00,0x23,0x00,0x01,0x1A,0x01,
PDU header: 
                            0:0x32,0x01,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,
plen: 32 dlen: 0
Parameter: 
                            0:0x04,0x03,0x12,0x08,0x82,0xA1,0x01,0x90,0x00,0x01,0x1A,0x01,0x12,0x08,0x82,0xA1,
                            10:0x00,0x23,0x00,0x01,0x1A,0x01,0x12,0x08,0x82,0xA1,0x00,0x05,0x00,0x01,0x1A,0x01,
PDU header: 
                            0:0x32,0x01,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,
plen: 42 dlen: 0
Parameter: 
                            0:0x04,0x04,0x12,0x08,0x82,0xA1,0x01,0x90,0x00,0x01,0x1A,0x01,0x12,0x08,0x82,0xA1,
                            10:0x00,0x23,0x00,0x01,0x1A,0x01,0x12,0x08,0x82,0xA1,0x00,0x05,0x00,0x01,0x1A,0x01,
                            20:0x12,0x08,0x82,0xA1,0x00,0x0F,0x00,0x01,0x1A,0x01,
PDU header: 
                            0:0x32,0x01,0x00,0x00,0x00,0x00,0x00,0x34,0x00,0x00,
plen: 52 dlen: 0
Parameter: 
                            0:0x04,0x05,0x12,0x08,0x82,0xA1,0x01,0x90,0x00,0x01,0x1A,0x01,0x12,0x08,0x82,0xA1,
                            10:0x00,0x23,0x00,0x01,0x1A,0x01,0x12,0x08,0x82,0xA1,0x00,0x05,0x00,0x01,0x1A,0x01,
                            20:0x12,0x08,0x82,0xA1,0x00,0x0F,0x00,0x01,0x1A,0x01,0x12,0x08,0x82,0xA1,0x00,0xA1,
                            30:0x00,0x01,0x1A,0x01,
PDU header: 
                            0:0x32,0x01,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x00,
plen: 62 dlen: 0
Parameter: 
                            0:0x04,0x06,0x12,0x08,0x82,0xA1,0x01,0x90,0x00,0x01,0x1A,0x01,0x12,0x08,0x82,0xA1,
                            10:0x00,0x23,0x00,0x01,0x1A,0x01,0x12,0x08,0x82,0xA1,0x00,0x05,0x00,0x01,0x1A,0x01,
                            20:0x12,0x08,0x82,0xA1,0x00,0x0F,0x00,0x01,0x1A,0x01,0x12,0x08,0x82,0xA1,0x00,0xA1,
                            30:0x00,0x01,0x1A,0x01,0x12,0x08,0x82,0xA1,0x26,0x4A,0x00,0x01,0x1A,0x01,
daveExecReadRequest(dc:000000001A84DB10, PDU:000000001A8302B0, rl:000000001A83A250
_daveExchange PDU number: 65536
ReadFromNck enter _daveExchangeTCP
send packet: : 
                            0:0x03,0x00,0x00,0x4F,0x02,0xF0,0x80,0x32,0x01,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,
                            10:0x00,0x04,0x06,0x12,0x08,0x82,0xA1,0x01,0x90,0x00,0x01,0x1A,0x01,0x12,0x08,0x82,
                            20:0xA1,0x00,0x23,0x00,0x01,0x1A,0x01,0x12,0x08,0x82,0xA1,0x00,0x05,0x00,0x01,0x1A,
                            30:0x01,0x12,0x08,0x82,0xA1,0x00,0x0F,0x00,0x01,0x1A,0x01,0x12,0x08,0x82,0xA1,0x00,
                            40:0xA1,0x00,0x01,0x1A,0x01,0x12,0x08,0x82,0xA1,0x26,0x4A,0x00,0x01,0x1A,0x01,
readISOpacket: 63 bytes read, 63 needed
readISOpacket: packet: 
                            0:0x03,0x00,0x00,0x3F,0x02,0xF0,0x80,0x32,0x03,0x00,0x00,0x00,0x00,0x00,0x02,0x00,
                            10:0x2A,0x00,0x00,0x04,0x06,0xFF,0x05,0x00,0x02,0x00,0xF4,0xFF,0x07,0x00,0x04,0x41,
                            20:0x9E,0x66,0x64,0xFF,0x06,0x00,0x02,0x00,0x02,0xFF,0x06,0x00,0x04,0x00,0x00,0x00,
                            30:0x00,0xFF,0x06,0x00,0x01,0x00,0x00,0xFF,0x05,0x00,0x04,0x00,0x00,0x00,0x00,
ReadFromNck _daveExchangeTCP res from read 63
result of exchange: 0
PDU header: 
                            0:0x32,0x03,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x2A,0x00,0x00,
plen: 2 dlen: 42
Parameter: 
                            0:0x04,0x06,
Data     : 
                            0:0xFF,0x05,0x00,0x02,0x00,0xF4,0xFF,0x07,0x00,0x04,0x41,0x9E,0x66,0x64,0xFF,0x06,
                            10:0x00,0x02,0x00,0x02,0xFF,0x06,0x00,0x04,0x00,0x00,0x00,0x00,0xFF,0x06,0x00,0x01,
                            20:0x00,0x00,0xFF,0x05,0x00,0x04,0x00,0x00,0x00,0x00,
Data hdr : 
                            0:0xFF,0x05,0x00,0x02,
Data     : 
                            0:0x00,0xF4,
Data hdr : 
                            0:0xFF,0x07,0x00,0x04,
Data     : 
                            0:0x41,0x9E,0x66,0x64,
Data hdr : 
                            0:0xFF,0x06,0x00,0x02,
Data     : 
                            0:0x00,0x02,
Data hdr : 
                            0:0xFF,0x06,0x00,0x04,
Data     : 
                            0:0x00,0x00,0x00,0x00,
Data hdr : 
                            0:0xFF,0x06,0x00,0x01,
Data     : 
                            0:0x00,
Data hdr : 
                            0:0xFF,0x05,0x00,0x04,
Data     : 
                            0:0x00,0x00,0x00,0x00,
error: ok
dave test result: p-param[0]: 4
daveExecReadRequest result 0: 0  444834384 65537 5197216
Store result 0 length:-202130528
daveExecReadRequest result 1: -202130528  444834384 65537 0
Store result 1 length:-202130528
daveExecReadRequest result 2: -202130528  444834384 65537 0
Store result 2 length:-202130528
daveExecReadRequest result 3: -202130528  444834384 65537 0
Store result 3 length:-202130528
daveExecReadRequest result 4: -202130528  444834384 65537 0
Store result 4 length:-202130528
daveExecReadRequest result 5: -202130528  444834384 65537 0
Store result 5 length:-202130528
daveUseResult(dc:000000001A84DB10, result set:000000001A83A250, number:0)
result set has 6 results
result error: 0
result length: 0
```


----------



## Thomas_v2.1 (7 April 2018)

Der Unterschied ist nur bei Transportgröße 5, bei allen anderen passt es ja.

Wie gesagt habe ich Logfiles von verschiedenen S7-Steuerungen wo die Größe hier anders interpretiert werden muss, und so ist es z.Zt. auch in Wireshark gemacht.


----------



## Hans54216 (7 April 2018)

Thomas_v2.1 schrieb:


> libnodave kannte die anderen Transportgrößen 5 und 7 überhaupt nicht, vermutlich haben wir das irgendwann mal ergänzt aber nicht bei der dump-Funktion?
> Bei einer S7 SPS braucht libnodave diese auch nicht zu kennen, weil wenn du bei der Anfrage angibst du möchtest 2 Bytes lesen, dann kommt auch niemals die Transportgröße 5 oder 7 zurück, sondern die SPS schickt dir auch Transportgröße Byte (dann ist die Anzahl in Bits). Frag mich nicht warum Siemens das überhaupt so vorgesehen hat.
> 
> Festzustellen ist, dass wenn du einen NC Bereich anfragst, die Transportgröße 5 anders zu interpretieren ist als bei einer S7-SPS. Bei Siemens muss man einiges einfach so hinnehmen wie es ist.



Nochmal zur Klarstellung:
Es wird zwar die Methode "ReadFromNck" verwendet, jedoch werden Drive Daten vom Sinamics Antrieb gelesen.
Auf Nck Daten (NC, Kanal, Achse,...) antwortet die NC immer als "Octet String".



Anhang anzeigen Nc Integer Parameter.rar


----------



## Hans54216 (7 April 2018)

Thomas_v2.1 schrieb:


> libnodave kannte die anderen Transportgrößen 5 und 7 überhaupt nicht, vermutlich haben wir das irgendwann mal ergänzt aber nicht bei der dump-Funktion?
> Bei einer S7 SPS braucht libnodave diese auch nicht zu kennen, weil wenn du bei der Anfrage angibst du möchtest 2 Bytes lesen, dann kommt auch niemals die Transportgröße 5 oder 7 zurück, sondern die SPS schickt dir auch Transportgröße Byte (dann ist die Anzahl in Bits). Frag mich nicht warum Siemens das überhaupt so vorgesehen hat.
> 
> Festzustellen ist, dass wenn du einen NC Bereich anfragst, die Transportgröße 5 anders zu interpretieren ist als bei einer S7-SPS. Bei Siemens muss man einiges einfach so hinnehmen wie es ist.



Brauch ich das jetzt für die SPS oder nicht?
Wenn ich es Auskommentiere funktioniert es zumindest für den Antrieb und für die Nck sowieso.


```
if ((*q==255)&&(rlen>4)) {
				len=q[2]*0x100+q[3];
				if (q[1]==4) {
					len>>=3;	/* len is in bits, adjust */
				} else if (q[1]==5) {			/* Fehlenden Size-Type INTEGER ergänzt */
		    		//len>>=3;	/* len is in bits, adjust */
```


----------



## Thomas_v2.1 (7 April 2018)

Ich glaube den Wert hatte ich mal ergänzt, falls optional symbolisch auf die 1200er zuzugreifen. Bei den aktuellen 1200ern funktioniert das aber eh wieder völlig anders.
Meiner Meinung nach kannst du es für deine Zwecke entfernen, dann sollte dein NC Zugriff funktionieren und auch der SPS Variablenzugriff, weil libnodave dort immer in Byte-Größen anfragt.

Ich weiß nur noch nicht was ich bei Wireshark mache, ich denke mal wenn dann wird man dort eher SPS Datenverkehr zu Gesicht bekommen. Ansonsten müsste ich schon zur Antwort die Anfrage heraussuchen, und wenn dort ein NCK Bereich angefragt wurde, dann die 5 anders interpretieren. Aber das ist nicht mal grad eben.


----------



## Jochen Kühner (10 April 2018)

Ich hatte in meinem libnodave fork ja den Symbolischen 1200er Zugriff eingebaut. Antwortet die SPS denn darauf immer mit 5? Oder ist das nur bei Integer Variablen so? (Teilt die SPS so die größe mit?) 

Geht es denn überhaupt wenn du libnodave änderst und mit "5" anträgst?


----------



## Hans54216 (18 Mai 2018)

Ich bin auf ein neues Problem gestoßen.

Wenn ich von der NC viele Variablen lese, werden diese automatisch in mehrere PDUs aufgeteilt.
Im konkreten Fall werden 300 LReal von der NC gelesen und die PDUs werden jeweils bei 77 gesplittet.

Wenn ich an die NC einen Lesebefehl für Drive-Daten schicke  bekomme ich bei mehr als 19 Variablen diese Fehlermeldung:
[Error code: This service is not implemented on the module or a frame error was reported (0x8104)]





Wo erfolgt das aufteilen auf mehrere PDUs? 

LibNoDave oder DotNetSiemensPlcToolBox


----------



## Rainer Hönle (18 Mai 2018)

Stell doch einmal das komplette wireshark-Log ein


----------



## Thomas_v2.1 (18 Mai 2018)

Die imho einzige Funktion die sich bei libnodave um die PDU Größen kümmert ist daveReadManyBytes. Im Normalfall ist also der Anwender von libnodave dafür verantwortlich die Funktionen so einzusetzen, dass die Protokollspezifikationen eingehalten werden. Was dann leider vorraussetzt, dass der Anwender überhaupt weiß wo die Beschränkungen sind. Diese "Low-Leveligkeit" war ja auch ein Grund warum der Jochen da noch eine Schicht darübergesetzt hat.

Ist bei den NC-Funktionen denn überhaupt schon aus der Anfrage ersichtlich wie groß der Antwortdatensatz werden wird? Wenn dort z.B. Zeichenketten bei angefragten Dateinamen zurückkommen, ist das im Gegensatz zu den Funktionen der S7 bei denen immer nur eine fixe Anzahl an Bytes gelesen werden nicht so einfach ersichtlich wie groß der Antwortdatensatz werden wird.

Aber wie Rainer schon schrieb, ein Wireshark Log von der Siemens Kommunikation ist nicht verkehrt. Vielleicht bietet die NC ja spezielle Funktionen dafür.


----------



## Jochen Kühner (20 Mai 2018)

Wenn du die ReadTags Funktion meiner Bibliothek verwendest, diese Splittet die Telegramme in mehrere PDUs auf. Dort gibt es auch keinen Spezialcode für deine NC Tags (außer du hast ihn eingebaut). 

Es gibt dort aber einiges an Logik wie Ich ermittle wie Ich die Daten am geschicktesten in PDUs packe...


----------



## Hans54216 (25 Mai 2018)

Ich verwende die ReadTags Funktion. Diese enthält schon kleine Anpassungen für die NC, wobei der Teil mit der PDU Größe bis jetzt gepasst hat.
Mit der NC hat NoDave ja ne PDU Größe von 960 ausgehandelt. Für die Feed Drive Daten ist jedoch bei 240 schluss.

Scheinbar tunnelt die NC die Drive anfragen und schickt sie dann per ProfiBus an den Antrieb.

Hab jetzt ne zusätzlich abfrage eingebaut und die maximale Größe dann auf 208 (240-32) verringert.


----------



## Jochen Kühner (25 Mai 2018)

Hans54216 schrieb:


> Ich verwende die ReadTags Funktion. Diese enthält schon kleine Anpassungen für die NC, wobei der Teil mit der PDU Größe bis jetzt gepasst hat.
> Mit der NC hat NoDave ja ne PDU Größe von 960 ausgehandelt. Für die Feed Drive Daten ist jedoch bei 240 schluss.
> 
> Scheinbar tunnelt die NC die Drive anfragen und schickt sie dann per ProfiBus an den Antrieb.
> ...



Machst du n Pull Request? Wäre cool wenn das bei mir auch funktionieren würde!


----------



## Rainer Hönle (26 Mai 2018)

Jochen Kühner schrieb:


> Machst du n Pull Request? Wäre cool wenn das bei mir auch funktionieren würde!



Was verstehst Du unter einem Pull-Request?


----------



## Heinileini (26 Mai 2018)

Poll-Request?


----------



## Jochen Kühner (27 Mai 2018)

Pull Request? Das er seine änderungen auf github eincheckt und einen pull request auf mein repo macht!


----------



## Rainer Hönle (27 Mai 2018)

Jochen Kühner schrieb:


> Pull Request? Das er seine änderungen auf github eincheckt und einen pull request auf mein repo macht!



Ich war der Meinung, das hätte was mit dem Protokoll zu tun ;-), an Git habe ich dabei nicht gedacht.


----------



## Hans54216 (16 November 2018)

Ich hab mal wieder was neues 

Mehre Maschinen (840d sl) sind per X150 (ProfiNet) verbunden und ich möchte darüber kommunizieren.
Lesen/Schreiben der NC und PLC funktioniert ganz normal. Beim Dateien Kopieren kommt es jedoch zum Fehler.

So wie es aussieht hängt es mit der Größe der Datei zusammen. Ob der Fehler nun in der Siemens Steuerung oder in der Lib passiert kann ich nicht sagen.

Ablauf:
- Datei "TestFile1" ("/_N_MPF_DIR/_N_TestFile1_MPF") in Steuerung laden
- Datei "TestFile1" aus Steuerung lesen
- Hier ist noch alles gut.

- Datei "TestFile2" ("/_N_MPF_DIR/_N_TestFile2_MPF") in Steuerung laden
- Datei "TestFile2" aus Steuerung lesen
- Fehler beim Upload, Datei kann in der Steuerung nicht geöffnet werden


Leser über X150 (Fehler)
Anhang anzeigen FileUpDownloadX150_20181116.rar



Lesen über X120 (Funktioniert)
Anhang anzeigen FileUpDownloadX120_20181116.rar


----------



## Thomas_v2.1 (16 November 2018)

Ist die Datei denn trotzdem in der Steuerung vorhanden?

Eine Fehlermeldung gab es von der Steuerung an keiner Stelle, sie beendet einfach direkt die Verbindung.
Was ist denn der Unterschied zwischen X120 und X150? Vielleicht musst du bei großen Dateien vor dem Upload eine kurze Zeit warten.


----------



## Hans54216 (16 November 2018)

Die Dateien "_N_TESTFILE1_MPF" und "_N_TESTFILE2_MPF" hab ich per SCP von der Steuerung geladen.

Datei kommt über beide Schnittstellen auf die Steuerung, jedoch sind über X150 in der größeren Datei Bytes am Ende Falsche Bytes drin. Gesamtlänge (anzahl an Bytes) ist gleich.
Steuerung sagt bei öffnen der Datei über X150 "Kann Binär Datei nicht öffnen". Daher wird wohl der Upload in der Steuerung auch crashen.

Die 840D sl hat drei Verschiedene Netzwerkbereiche
X120: Maschinennetz
X130: Anlagennetz (Firmennetz)
X150: Maschinenvernetzung ProfiNet


----------



## Thomas_v2.1 (16 November 2018)

Hast du die Möglichkeit zu testen ab welcher Dateigröße es nicht mehr funktioniert?

Es gibt im Telegramm beim Download noch 2 unbekannte Bytes, wo an einer Stelle 0x00fb / dez 251 eingetragen wird. Vielleicht hat der Wert doch irgendeine Bewandtnis. Deine funktionierende Datei ist 199 Bytes groß und die nicht funktionierende 267. Das liegt also einmal unter und einmal über dem Wert.
Von den PDU-Größen verhalten sich laut deinen Logfiles beide Schnittstellen gleich.


----------



## Thomas_v2.1 (16 November 2018)

Ich habe da eine Fährte.
Und zwar bei der Übertragung wo du sagst es fangen fehlerhafte Daten an, ist dieses ab Byte 169.
Im S7-Protokoll für den NC-Transfer gibt es 10 Bytes Header + 12 Bytes Parameter + 6 Bytes Data-Header + 43 Bytes Dateiheader für den Filetransfer. Da sind wir bei 240 Bytes, und das riecht doch stark nach einer S7-PDU-Größe.

Meine Vermutung ist darum, dass die Datenverbindung auf der betroffenen Schnittstelle intern über einen Kanal geleitet/geroutet wird, der nur 240 Bytes große PDUs beherrscht, auch wenn die Schnittstelle nach außen sagt, sie könne 960. Du könntest mal versuchen in libnodave die PDU Größe auf 240 Bytes zu setzen und dann die Daten zu übertragen. Ich vermute mal, es wird damit funktionieren.


----------



## Hans54216 (17 November 2018)

Genau das ist des Rätsels Lösung. Das Problem hatte ich schon mit Drive Daten, wobei da bei jeder Schnittstelle die PDU Größe auf 240 Bytes reduziert werden muss.

Da ich bei den Drivedaten anhand der Zieladresse diese Identifizieren kann, ist es leicht nur für diese die PDU Größe zu reduzieren.

Bei den Datei Up/Downloads hab ich nun die Schwierigkeit, dass das Ziel das NC Dateisystem ist und die PDU Größe von der Schnittstelle abhängig ist. Ich kann also pauschal die Größe verringern, damit es funktioniert oder ich finde ein Kriterium mit der ich erkennen kann an welcher Schnittstelle ich stecke.


----------



## Hans54216 (17 November 2018)

Bei "davePutNCProgram" hab ich die Funktion "daveGetMaxPDULen(dc)" wo ich prüfen kann ob die PDU größer als 240 ist und dann verringern. Wo muss ich beim "daveGetNcFile" und bei "daveGetNCProgram" die PDU Größe verringern?

Anhang anzeigen libnodave_20181117.rar


----------



## Thomas_v2.1 (17 November 2018)

Ich würde beim Verbindungsaufbau ganz einfach eine PDU von 240 Bytes vorschlagen, dann wissen beide Partner davon. Der Wert steht in der Struktur daveConnection in maxPDUlength. Der Wert wird in daveNewConnection in deinem Fall auf 960 initialisiert, und dann im Ablauf der Connect-Routine ausgehandelt. Wenn du den Wert maxPDUlength direkt vor dem Aufruf von Connect auf 240 setzt, dann sollte das funktionieren.


----------



## Hans54216 (17 November 2018)

Ich schau mal wie es sich bei NC Variablen verhält. Vielleicht bau ich nen Übergabeparameter für maxPDUlength ein. Ich will ja nicht grundsätzlich auf den Vorteil der größeren PDU verzichten.


----------



## Thomas_v2.1 (17 November 2018)

Unterstützt die NC eigentlich auch das Abfragen von Informationen über die Systemzustandslisten (SZL)?
Evtl. lässt sich darüber diese "Systemeigenschaft" erkennen, die SZL-Funktionen sind in libnodave schon vorhanden.

Um zu prüfen was geht, kannst du dir erst einmal ausgeben lassen welche SZL-IDs überhaupt unterstützt werden.
Diese Information erhältst du, wenn du eine Anfrage mit SZL-ID=0 und SZL-Index=0 stellst. In der Antwort erhältst du dann eine Liste mit allen unterstützten IDs.
Beispielsweise lässt sich in ID=0x0131 Index=1 nochmal die Max. PDU Größe abfragen, wenn dort bei der einen Schnittstelle 960 und bei der anderen 240 steht, dann wäre das ein entsprechendes Kriterium.

Aber teste doch erst einmal ob es wirklich mit der 240er PDU funktioniert. Eigentlich wäre es dann ein Fehler in der Steuerung den man selber umgehen muss.


----------



## Peter Gedöns (17 November 2018)

Thomas_v2.1 schrieb:


> Eigentlich wäre es dann ein Fehler in der Steuerung den man selber umgehen muss.




Eigentlich ist der Fehler das es überhaupt geht. Es ist nicht gewollt vom Profinet X150 in die NC zugreifen zumindest nicht in das NC Filesystem
ich weiß nicht mit welcher Version der Hans da Testet aber mit den letzten Softwareständen ist auch das Linuxbase angepasst worden.
man hatte gemerkt das man etwas Richtung Netzwerk Sicherheit tun muss.


----------



## Hans54216 (17 November 2018)

Peter Gedöns schrieb:


> Eigentlich ist der Fehler das es überhaupt geht. Es ist nicht gewollt vom Profinet X150 in die NC zugreifen zumindest nicht in das NC Filesystem
> ich weiß nicht mit welcher Version der Hans da Testet aber mit den letzten Softwareständen ist auch das Linuxbase angepasst worden.
> man hatte gemerkt das man etwas Richtung Netzwerk Sicherheit tun muss.



Ich teste mit v4.7.6.1 und v4.8.2, welche jetzt nicht gerade veraltet sind. Bei v4.7.3 weiß ich dass Siemens an der Linuxbase rumgebastelt hat und einige Fehler eingebaut hat, sodass selbst die eigenen HMI Funktionen nicht mehr funktionierten. Mir ist aber nicht bekannt dass bei S7comm etwas angelangt wurde.
Was nicht funktioniert ist der SCP Zugriff über X150.



Thomas_v2.1 schrieb:


> Aber teste doch erst einmal ob es wirklich mit der 240er PDU funktioniert.  _Eigentlich wäre es dann ein Fehler in der Steuerung den man selber umgehen muss._


Ich hab nun zunächst viele NC Variablen gelesen (960 PDU Größe), dabei bekomme ich ebenfalls einen Fehler. Anschließend hab ich die maximale PDU Größe auf 240 gesetzt und siehe da, alles funktioniert. Somit ist das wohl ein Fehler der Steuerung, dass sie über diese Schnittstelle keine kleinere PDU Größe aushandelt.

Ich hab dann die SZL0,0 der NC ausgelesen. NC sendet zwar Daten, jedoch kann LibNoDave mit diesen noch nichts anfangen.

Anhang anzeigen NC_SZL.rar


----------



## Thomas_v2.1 (17 November 2018)

Hans54216 schrieb:


> Ich hab dann die SZL0,0 der NC ausgelesen. NC sendet zwar Daten, jedoch kann LibNoDave mit diesen noch nichts anfangen.


Interpretieren musst du die SZL-Datensätze selber, viele davon sind in dem Dokument für die Siemens Standardfunktionen auch beschrieben.
In Wireshark habe ich nicht alle, aber vor allem die interessanten (zumindest für mich) SZL-Datensätze dekodiert. Laut Aufzeichnung hat die NC u.a. auch was unter SZL-ID 0x0131 anzubieten, du kannst ja mal direkt mit ID=0x0131 Index=1 eine Anfrage starten und gucken was kommt, dieser Datensatz wird auch in Wireshark dekodiert.


----------



## Hans54216 (17 November 2018)

Thomas_v2.1 schrieb:


> Interpretieren musst du die SZL-Datensätze selber, viele davon sind in dem Dokument für die Siemens Standardfunktionen auch beschrieben.


Das es die SZL selber interpretieren muss ist mir klar, jedoch bringt LibNoDave "-129" als result und der Buffer ist leer.



Thomas_v2.1 schrieb:


> Laut Aufzeichnung hat die NC u.a. auch was unter SZL-ID 0x0131 anzubieten, du kannst ja mal direkt mit ID=0x0131 Index=1 eine Anfrage starten und gucken was kommt, dieser Datensatz wird auch in Wireshark dekodiert.


Auf diese ID kommt "Return code: Object does not exist (0x0a)"

Für ID 0x0111 Index 0x0001 bekomme ich eine Antwort die von WireShark dekodiert wird. LibNoDave bring jedoch wieder ret = -129


```
daveReadSZL(dc:005CDBC0, ID:273, index:1, buffer:01B308B8)adding user data header.
dCount: 0
dCount: 4
PDU header: 
                            0:0x32,0x07,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x08,
plen: 8 dlen: 8
Parameter: 
                            0:0x00,0x01,0x12,0x04,0x11,0x44,0x01,0x00,
Data     : 
                            0:0xFF,0x09,0x00,0x04,0x01,0x11,0x00,0x01,
_daveExchange PDU number: 65536
PI_DienstNC enter _daveExchangeTCP
send packet: : 
                            0:0x03,0x00,0x00,0x21,0x02,0xF0,0x80,0x32,0x07,0x00,0x00,0x00,0x00,0x00,0x08,0x00,
                            10:0x08,0x00,0x01,0x12,0x04,0x11,0x44,0x01,0x00,0xFF,0x09,0x00,0x04,0x01,0x11,0x00,
                            20:0x01,
readISOpacket: 69 bytes read, 69 needed
readISOpacket: packet: 
                            0:0x03,0x00,0x00,0x45,0x02,0xF0,0x80,0x32,0x07,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,
                            10:0x28,0x00,0x01,0x12,0x08,0x12,0x84,0x01,0xB6,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,
                            20:0x24,0x01,0x11,0x00,0x01,0x00,0x1C,0x00,0x01,0x00,0x00,0x36,0x46,0x43,0x35,0x33,
                            30:0x37,0x33,0x2D,0x30,0x41,0x41,0x33,0x30,0x2D,0x30,0x41,0x42,0x30,0x00,0x00,0x58,
                            40:0xCF,0x00,0x07,0x11,0x01,
PI_DienstNC _daveExchangeTCP res from read 69
result of exchange: 0
*** res of _daveExchange(): 0
PDU header: 
                            0:0x32,0x07,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x28,
plen: 12 dlen: 40
Parameter: 
                            0:0x00,0x01,0x12,0x08,0x12,0x84,0x01,0xB6,0x00,0x00,0x00,0x00,
Data     : 
                            0:0xFF,0x00,0x00,0x24,0x01,0x11,0x00,0x01,0x00,0x1C,0x00,0x01,0x00,0x00,0x36,0x46,
                            10:0x43,0x35,0x33,0x37,0x33,0x2D,0x30,0x41,0x41,0x33,0x30,0x2D,0x30,0x41,0x42,0x30,
                            20:0x00,0x00,0x58,0xCF,0x00,0x07,0x11,0x01,
PDU header: 
                            0:0x32,0x07,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x28,
plen: 12 dlen: 40
Parameter: 
                            0:0x00,0x01,0x12,0x08,0x12,0x84,0x01,0xB6,0x00,0x00,0x00,0x00,
Data     : 
                            0:0xFF,0x00,0x00,0x24,0x01,0x11,0x00,0x01,0x00,0x1C,0x00,0x01,0x00,0x00,0x36,0x46,
                            10:0x43,0x35,0x33,0x37,0x33,0x2D,0x30,0x41,0x41,0x33,0x30,0x2D,0x30,0x41,0x42,0x30,
                            20:0x00,0x00,0x58,0xCF,0x00,0x07,0x11,0x01,
*** res of _daveSetupReceivedPDU(): 0000
fixme: what to do with data type 0?
*** res of _daveTestPGReadResult(): FFFFFF7F
result of daveReadSZL(1): -129
```


----------



## Thomas_v2.1 (17 November 2018)

Hans54216 schrieb:


> Das es die SZL selber interpretieren muss ist mir klar, jedoch bringt LibNoDave "-129" als result und der Buffer ist leer.


Das liegt an der TransportSize=0 mit der die NC antwortet. Man kennt ja die Spezifikation für das Protokoll nicht, alle anderen S7-Gerätschaften geben aber 0 nur aus wenn die Datenlänge auch 0 ist, zumindest in allen Aufzeichnungen die ich bisher so gesehen habe. Bei der NC steht 0 aber wohl auch für Transportgröße Byte. Aufgrund der Tatsache, dass da auch andere Teile nicht ganz sauber in der NC umgesetzt wurden, würde ich das mal als Fehler oder im Siemens-Sprech "Systemunschärfe" ansehen.

Schade, dass die SZL ID 0x131/1 nicht funktioniert. So auf Anhieb habe ich auch keine Idee woran du diesen Unterschied sonst noch festmachen könntest.


----------



## TobiasA (3 Januar 2019)

Guten Morgen und ein frohes neues Jahr!

Gibt es ein offizielles Release von Libnodave mit dem Up/Download von NC-Dateien, das ich in eigenen C++ Code einbetten / linken darf?

Vielen Dank!


----------



## Thomas_v2.1 (3 Januar 2019)

TobiasA schrieb:


> Gibt es ein offizielles Release von Libnodave mit dem Up/Download von NC-Dateien, das ich in eigenen C++ Code einbetten / linken darf?


Ich weiß nicht wie viele von den Funktionen Jochen Kühner in seine Bibliothek eingebaut hat, ein paar sind aber vorhanden:

https://github.com/dotnetprojects/DotNetSiemensPLCToolBoxLibrary


----------



## TobiasA (3 Januar 2019)

Thomas_v2.1 schrieb:


> Ich weiß nicht wie viele von den Funktionen Jochen Kühner in seine Bibliothek eingebaut hat, ein paar sind aber vorhanden:
> 
> https://github.com/dotnetprojects/DotNetSiemensPLCToolBoxLibrary



Gut, dann könnte ich ja seine fertige DLL nehmen und in mein Programm linken- und es dann ebenfalls unter die GNU stellen.
Ich möchte ein Kommandozeilentool zum Transfer von Programmen erstellen. Das geht zwar auch mit PSCP, allerdings "verschluckt" sich dann manchmal das Zeilenende und fehlt einfach. Derzeit übertrage ich einfach so lange, bis es passt- aber das ist ja hochgradig semiprofessionell und keine saubere Lösung.
Und an einer virtuellen NC geht es natürlich auch nicht, da die kein Filesystem auf der Karte hat.
Es wäre nur ein kleiner Schritt zum Debugger für Zyklen, wenn man so was wie GUD's lesen kann... Was sehr angenehm wäre.
Werde die nächsten Wochen und Monate mal ein bisschen experimentieren, vielleicht kommt ja was bei rum.

Vielen Dank!


----------



## Peter Gedöns (3 Januar 2019)

TobiasA schrieb:


> Und an einer virtuellen NC geht es natürlich auch nicht, da die kein Filesystem auf der Karte hat.
> Es wäre nur ein kleiner Schritt zum Debugger für Zyklen, wenn man so was wie GUD's lesen kann... Was sehr angenehm wäre.


  von welcher virtuellen NC redest Du ?  VNCK oder Sinutrain


----------



## TobiasA (3 Januar 2019)

Peter Gedöns schrieb:


> von welcher virtuellen NC redest Du ?  VNCK oder Sinutrain



VNCK, ab Operate.


----------



## Peter Gedöns (3 Januar 2019)

das Filesystem ist da schon vorhanden.
was da fehlt ist der Server für de SSH FTP verbindung


----------



## TobiasA (3 Januar 2019)

Peter Gedöns schrieb:


> das Filesystem ist da schon vorhanden.
> was da fehlt ist der Server für de SSH FTP verbindung



Kann man den nachträglich einrichten? Filesystem muss es ja prinzipiell geben, nur hin gekommen bin ich nicht.


----------



## Peter Gedöns (3 Januar 2019)

ich habe gerade keine VNCK zur Hand , denke aber das die Funktionen nicht im NCK liegen sondern eher in BS der NCU und das fehlt bei dir ja.
deswegen würde ich mal tippen keine Möglichkeiten.


----------



## TobiasA (3 Januar 2019)

Hmm... Ein HMI kommt von außen drauf, also über den CAP-Server müsste man prinzipiell drauf kommen- dächte ich so in meinem nicht mehr ganz jugendlichen Leichtsinn.
Daher wäre meine Hoffnung ja, dass Libnodave hier den gleichen Weg wie CAP (bzw. HMI) nimmt und somit das interne Filesystem über den gleichen Weg erreicht wie das HMI.

Probieren geht über studieren... Mal schauen was ich so hinkriege.


----------



## Peter Gedöns (3 Januar 2019)

Der HMI geht über den CAP , die SSH /FTP ist ja nur dazu gedacht um von außen auf die NCU zukommen.
Ich habe mir den Weg den Libnodave nimmt nicht angeschaut aber ich denke die Verbindung läuft über den Port 102.
Hatte ja schon mal meine Bedenken geäußert das dieser zugriff auf das NCK Filesystem nicht gewollt ist und gegeben falls nicht mehr geht bei neueren  NC Versionen.
hast du die HMI OA Software ? wenn ja könntest de dir ja da die CAP zugriffe auf das Filesystem anschauen.


----------



## Hans54216 (7 Januar 2019)

In der LibNoDave ist der Zugriff auf das Filesystem analog zur HMI per Port 102 und S7Comm programmiert.


----------



## Hans54216 (21 Januar 2019)

Hat schon jemand den Peripherie Zugriff programmiert?

z.B. PEW3000


----------



## Hans54216 (21 Januar 2019)

Ich hab mir mal die Kommunikation der Step7 Variablentabelle angesehen. So wie es aussieht wird für das PEW3000 ein Event angemeldet. Antwort kommt dann als Push-Undef -> VarTab.
Die Normale VarTab Funktion meldet "Object does not exist".








Anhang anzeigen PEW3000.rar


----------



## Thomas_v2.1 (21 Januar 2019)

Funktioniert das Lesen mit Libnodave denn nicht mit einer entsprechenden Bereichsangabe wie daveP bzw. 0x80?

Das mit "Push-Undef" habe ich in der letzten Wireshark Version behoben, dort wird dann "Push-Res" für Response angezeigt. Die Variablentabellenfunktionen habe aber ich nicht bis ins letzte Detail ausgearbeitet, wenn ich mich recht erinnere war das relativ verwoben und je nach CPU auch noch unterschiedlich umgesetzt. Die Triggerbedingungen wie Zyklusbeginn, Zyklusende usw. stecken da auch noch mit drin.


----------



## Hans54216 (22 Januar 2019)

Ich hab mir gestern mal die Lib genau angesehen und bin auf die 0x80 (Periphery) gestoßen. Diese wurde beim Interpretieren der PLC Adresse (DotNetSiemensPLCToolBoxLibrary) nicht betrachtet.
Durch die Änderung kann ich nun PEx lesen.
Weißt du wie ich PAx lesen kann?


----------



## Rainer Hönle (22 Januar 2019)

Gar nicht. Kann nur geschrieben werden mittels 0x80.


----------



## Jochen Kühner (24 Januar 2019)

@Hans ist da noch ein Fehler in meiner Lib?


----------



## Hans54216 (24 Januar 2019)

Jochen Kühner schrieb:


> @Hans ist da noch ein Fehler in meiner Lib?



0x80 (Periphery) ist zwar als enum vorhandeln, wird jedoch nicht verwendet. Laut Kommentar ist es auch nicht im Tag zulässig.

Hab das interpretieren der PLC Adresse angepasst (ergänzt).
Ich mach bei zeiten wieder nen Pull request von meim Fork.


----------



## Thomas_v2.1 (17 Februar 2019)

Funktioniert der Dateidownload eigentlich mit den ergänzten Funktionen in libnodave fehlerfrei bei großen wie auch bei kleinen Dateien?

Mir ist bei den mir vorliegenden Logfiles aus diesem Thread nämlich eine kleine Unstimmigkeit aufgefallen.
Und zwar wird der eigentlichen Datei u.a. die Dateilänge als ASCII vorangestellt. In der Funktion die ich ergänzt habe, berechne ich die Längenangabe aus der Länge der Datei plus der Länge der Pfadangabe.

Jetzt habe ich hier eine Aufzeichnung "NC_File_Download" bei der diese Berechnung auch stimmt (Daten=20, Pfad=19, Vorab=39), aber bei der Aufzeichnung "NC_File_Big_Download" in der die gesamte Datei auf mehrere PDUs aufgeteilt wird, stimmt die Berechnung überhaupt nicht (Daten=8918, Pfad=34, Vorab=8934). Screenshots davon im Anhang.

Oder diese Längenangabe ist überhaupt nicht von Relevanz, wenn der Download trotzdem funktioniert.

Das ist mir aufgefallen, weil ich in Wireshark das Zusammensetzen der Datenteile aus fragmentierten Dateien ergänzt habe, und eigentlich die Länge vorab für die Größe der Datei verwenden wollte, was aber nicht bei allen Dateien die ich von NC Down-/Upload Transaktionen habe, funktioniert.


----------



## Thomas_v2.1 (17 Februar 2019)

Hilft doch manchmal das Problem nochmal aufzuschreiben. Ist alles richtig umgesetzt, bei den NC Funktionen gibt es im Dateiteil in jedem Fragment nochmal diese zwei Bytes 0x00, 0xfd unbekannter Funktion.
Da kommt dann die Rechnung hin, wenn ich 9*2 = 18 Bytes davon abziehe.

Dann habe ich aber noch eine Aufzeichnung "NC_File_Big_Download2", bei dem vor dem Download noch eine Upload Anforderung ist, da stehen in der Dateilänge wiederum nur Leerzeichen. Der Inhalt sieht dann auch nicht nach Datei aus, sondern nach einer Art Verzeichnisauflistung. Gibt es sowas?


----------



## Hans54216 (18 Februar 2019)

Thomas_v2.1 schrieb:


> Dann habe ich aber noch eine Aufzeichnung "NC_File_Big_Download2", bei dem vor dem Download noch eine Upload Anforderung ist, da stehen in der Dateilänge wiederum nur Leerzeichen. Der Inhalt sieht dann auch nicht nach Datei aus, sondern nach einer Art Verzeichnisauflistung. Gibt es sowas?



Wenn man einen Upload auf einen Ordner/Verzeichnis macht, schickt die NC ein File mit den Namen der Dateien und Ordner in diesem Pfad.


----------



## Thomas_v2.1 (18 Februar 2019)

Hans54216 schrieb:


> Wenn man einen Upload auf einen Ordner/Verzeichnis macht, schickt die NC ein File mit den Namen der Dateien und Ordner in diesem Pfad.



Ich glaube du hattest in diesem Thread mal geschrieben, die Pfadangabe könne maximal 32 Zeichen lang sein. So viel Platz habe ich in der ergänzten Funktion die ich hier gepostet habe auch vorgesehen.

Bei der Verzeichnisanfrage sind aber laut einem Logfile was ich von dir habe auch längere Angaben möglich. In einer Aufzeichnung mit einem Upload und ;$PATH=/_N_wks_dir/_N_G_GQ_TEST_SWITCH_VCS_WPD sind es 40 Zeichen. Es wäre also sinnvoll das auch in der Funktion zu erweitern, andernfalls wird die Pfadangabe abgeschnitten und es kommt vermutlich ein Fehler zurück.


----------



## Hans54216 (19 Februar 2019)

Thomas_v2.1 schrieb:


> Ich glaube du hattest in diesem Thread mal geschrieben, die Pfadangabe könne maximal 32 Zeichen lang sein. So viel Platz habe ich in der ergänzten Funktion die ich hier gepostet habe auch vorgesehen.



Nicht die Pfadangabe, sondern ein Dateiname/Ordner können maximal 31 Zeichen + Nullterminierung lang sein.



Thomas_v2.1 schrieb:


> Bei der Verzeichnisanfrage sind aber laut einem Logfile was ich von dir habe auch längere Angaben möglich. In einer Aufzeichnung mit einem Upload und ;$PATH=/_N_wks_dir/_N_G_GQ_TEST_SWITCH_VCS_WPD sind es 40 Zeichen. Es wäre also sinnvoll das auch in der Funktion zu erweitern, andernfalls wird die Pfadangabe abgeschnitten und es kommt vermutlich ein Fehler zurück.


Für den Up- oder Download muss zunächst ein PI-Dienst mit der Pfadangabe ausgeführt werden. Im Up/Download selbst wird nur der Dateiname angegeben. In diesem Fall 27 Zeichen + \0.


----------



## KES_CK (20 Februar 2019)

@Hans54216
danke für das super code snippet!
Das laden und interpretieren der unterschiedlichen ACX-Files klappt hervorragend!
Das lesen von selbst angelegten GUD's => MGUD, UGUD, GD4-GD9 sowohl Global und Kanalspezifisch funktioniert.
Beim versuch z.B. GUD's aus dem Bereich Global SGUD oder denen die über MD18660 im Baustein MGUD (SYG_RM) angelegten wurden zu lesen wird im PLCNckTag ItemDoesNotExist=true gesetzt.
Das Lesen über die PLC mit FB5 klappt normal.
Hast Du in dem Bereich auch schon mal versucht was zu lesen?


----------



## Hans54216 (21 Februar 2019)

Über X130 (Firmennetz) funktioniert die alte Upload Methode mit neuen Software Ständen nicht mehr.
Mit der neuen Variante (NC sendet mehrer Pakete ohne Bestätigung) kommt es bei INI Dateien zum Fehler in LibNoDave.

Anhang anzeigen IniFileUpload_20190221.rar


Vom HMI hochgeladen (andere INI): 
	

		
			
		

		
	

Anhang anzeigen IniFileUpload_HMI_20190221.rar


----------



## Thomas_v2.1 (21 Februar 2019)

Die Zählung von unackcount ist nicht richtig, das erste Paket außerhalb der while-Schleife wird nicht mitgezählt.
Wenn du nach tot_len += part_len; und vor while... ein unackcount++; einfügst sollte es richtig gezählt werden. Zumindest in dem Stand der Funktion die ich habe. Vermutlich ist der Fehler in der anderen Funktion daveGetNcFileSize ebenfalls vorhanden.

Hat das denn schon einmal funktioniert, oder wurden bisher nur noch keine Dateien geladen die mehr als 20 PDUs benötigen und es ist darum nicht aufgefallen?


----------



## Hans54216 (21 Februar 2019)

Ich werd das morgen testen.



Thomas_v2.1 schrieb:


> Hat das denn schon einmal funktioniert, oder wurden bisher nur noch keine Dateien geladen die mehr als 20 PDUs benötigen und es ist darum nicht aufgefallen?



Ich hab schon alle Größen geladen, jedoch nur von echten Programmen (PI-Dienst F_XFER). Hab letztens ja geschrieben, dass der wireshark anders aussieht wie vom HMI. Bei Programmen ist die NC da wohl nicht so gleinlich.


----------



## Hans54216 (21 Februar 2019)

KES_CK schrieb:


> @Hans54216
> danke für das super code snippet!
> Das laden und interpretieren der unterschiedlichen ACX-Files klappt hervorragend!
> Das lesen von selbst angelegten GUD's => MGUD, UGUD, GD4-GD9 sowohl Global und Kanalspezifisch funktioniert.
> ...



Schau ich mir morgen an, muss aber funktionieren.


----------



## Thomas_v2.1 (21 Februar 2019)

Apropos PI-Dienste: Wozu dient eigentlich _N_F_PROR?
Dazu gab es schon mal einen Thread, aber ergebnislos.


----------



## Hans54216 (21 Februar 2019)

Thomas_v2.1 schrieb:


> Apropos PI-Dienste: Wozu dient eigentlich _N_F_PROR?
> Dazu gab es schon mal einen Thread, aber ergebnislos.


Ich werd mal ne anfrage bei Siemens starten. Die Theorie is das es irgend welche Zugriffsrechte setzt, wobei er nicht dokumentiert ist. Das HMI startet ihn auf alle möglichen Dateien, wobei er immer wieder negativ (Fehlerhaft) quittiert wird.


----------



## Thomas_v2.1 (21 Februar 2019)

Hans54216 schrieb:


> Ich werd mal ne anfrage bei Siemens starten. Die Theorie is das es irgend welche Zugriffsrechte setzt, wobei er nicht dokumentiert ist. Das HMI startet ihn auf alle möglichen Dateien, wobei er immer wieder negativ (Fehlerhaft) quittiert wird.



Die Fehlermeldung der Antwort kann ich leider nicht aufschlüsseln, sonst wäre das auch hilfreich.
Ich hatte mir auch gerade so überlegt PROT = Protection setzen, und PROR = Protection remove oder etwas in der Richtung.
Wenn ich die Parameter so interpretiere wie _N_F_PROT dann stünden im 3. Parameter bei Protection fünf Unterstriche _____


----------



## Thomas_v2.1 (21 Februar 2019)

Hans54216 schrieb:


> Ich hab schon alle Größen geladen, jedoch nur von echten Programmen (PI-Dienst F_XFER). Hab letztens ja geschrieben, dass der wireshark anders aussieht wie vom HMI. Bei Programmen ist die NC da wohl nicht so gleinlich.



Ich habe noch eine Aufzeichnung eines Uploads von dir über die libnodave Funktionen gefunden. Das scheint doch richtig gewesen zu sein so wie es ist, nur gibt es bei deiner aktuellen Version einen Unterschied wie die NC sich verhält.

Bisher:
-> Request Start Upload (0x11, 0x7f, 0x06)
<- Response Start Upload (0x12, 0xbf, 0x06)
<- Dann NC Push-Response Upload (0x12, 0x3f, 0x07) und diese Anzahl muss gezählt werden, so wie es jetzt gemacht wurde und der Aufzeichnung nach auch funktioniert.

Deine neue Aufzeichnung
-> Request Start Upload (0x11, 0x7f, 0x06)
<- Direkt NC Push-Response (0x12, 0x3f, 0x07) und dann ab hier zählen

Ich habe überhaupt nicht überprüft ob der Funktionscode in der Antwort richtig ist. Das sollte man aber wohl tun, und nur wenn in der ersten Antwort (0x12, 0x3f, 0x07) dann unackcount um 1 inkrementieren. Es ließe sich auch anstelle die Telegramme zu zählen auf die Nummer reagieren die mitgeschickt wird, aber letztlich kommt es auf das gleiche raus.


----------



## Hans54216 (25 Februar 2019)

Thomas_v2.1 schrieb:


> Bisher:
> -> Request Start Upload (0x11, 0x7f, 0x06)
> <- Response Start Upload (0x12, 0xbf, 0x06)
> <- Dann NC Push-Response Upload (0x12, 0x3f, 0x07) und diese Anzahl muss gezählt werden, so wie es jetzt gemacht wurde und der Aufzeichnung nach auch funktioniert.


Upload mit Anpassung:
Anhang anzeigen BigFileUpload_v4_8_4_1_20190222.rar




Thomas_v2.1 schrieb:


> Deine neue Aufzeichnung
> -> Request Start Upload (0x11, 0x7f, 0x06)
> <- Direkt NC Push-Response (0x12, 0x3f, 0x07) und dann ab hier zählen


Upload mit Anpassung:
Anhang anzeigen IniFileUpload_v4_8_4_1_20190225.rar




Thomas_v2.1 schrieb:


> Ich habe überhaupt nicht überprüft ob der Funktionscode in der Antwort richtig ist. Das sollte man aber wohl tun, und nur wenn in der ersten Antwort (0x12, 0x3f, 0x07) dann unackcount um 1 inkrementieren. Es ließe sich auch anstelle die Telegramme zu zählen auf die Nummer reagieren die mitgeschickt wird, aber letztlich kommt es auf das gleiche raus.


Sollte das noch rein?


----------



## Hans54216 (25 Februar 2019)

KES_CK schrieb:


> @Hans54216
> danke für das super code snippet!
> Das laden und interpretieren der unterschiedlichen ACX-Files klappt hervorragend!
> Das lesen von selbst angelegten GUD's => MGUD, UGUD, GD4-GD9 sowohl Global und Kanalspezifisch funktioniert.
> Beim versuch z.B. GUD's aus dem Bereich Global SGUD




```
SGUD = 0x36,
PGUD = 0x36,    //= SGUD
GUD1 = 0x36     //= SGUD
```
_N_NC_GD1_ACX, _N_CH_GD1_ACX
Funktioniert bei mir genau so wie die anderen Bereiche.



KES_CK schrieb:


> oder denen die über MD18660 im Baustein MGUD (SYG_RM) angelegten wurden zu lesen wird im PLCNckTag ItemDoesNotExist=true gesetzt.
> Das Lesen über die PLC mit FB5 klappt normal.
> Hast Du in dem Bereich auch schon mal versucht was zu lesen?


Kannst du die SYG_RM per FB5 lesen? Wenn ja, was steht auf der Struktur "VarToken"?


----------



## Hans54216 (25 Februar 2019)

Die SYG Variablen können auch ganz normal gelesen/geschrieben werden


----------



## Thomas_v2.1 (25 Februar 2019)

Hans54216 schrieb:


> Sollte das noch rein?


Ich schätze mal ja, denn ich vermute mal mit deiner Änderung jetzt wird es an der alten Steuerung nicht mehr funktionieren.


----------



## KES_CK (27 Februar 2019)

Hans54216 schrieb:


> ```
> SGUD = 0x36,
> PGUD = 0x36,    //= SGUD
> GUD1 = 0x36     //= SGUD
> ...



Ich kann die Daten per FB5 ohne Probleme lesen aber beim lesen über die Lib bekommen ich als Value immer null zurückgeliefert
Bereich SGUD GUD-Variable _F_NCK_CL_ANG[0]
Step7:


C#:



Das gleiche Verhalten beim lesen der SYG_RM[0]
Step7:


C#:


----------



## Hans54216 (27 Februar 2019)

KES_CK schrieb:


> Ich kann die Daten per FB5 ohne Probleme lesen aber beim lesen über die Lib bekommen ich als Value immer null zurückgeliefert
> Bereich SGUD GUD-Variable _F_NCK_CL_ANG[0]
> Step7:
> Anhang anzeigen 44655
> ...



Durch die Abfrage _gud.IsArray ? 0x0 : 0x1 bekommst du als Zeile 0.

Nun muss du noch die Nummer (Index+1) hinzuzählen.

ncVar.GetNckTag(0,1) für Index 0


----------



## KES_CK (28 Februar 2019)

Hans54216 schrieb:


> Durch die Abfrage _gud.IsArray ? 0x0 : 0x1 bekommst du als Zeile 0.
> 
> Nun muss du noch die Nummer (Index+1) hinzuzählen.
> 
> ...



Perfekt, das war mein Fehler. Jetzt klappt alles 

Welchen ACX-File muss ich denn laden um die LUD's zu interpretieren?
bzw. welchen Code muss ich verwenden:

```
SGUD = 0x36,
PGUD = 0x36,    //= SGUD
GUD1 = 0x36     //= SGUD
LUD  = ???
```

Dann habe ich noch ein weiteres Problem bei dem ich anscheinend noch Fehler mache.
Ich bekomme keinen PI-Dienst gestartet. z.B. LOGIN oder LOGOUT bei meinen bisherigen Versuchen bekomme ich immer nur eine Exception.
Hier meine Versuche:

```
_myConn.PI_Service("_N_LOGIN_", new string[] { "P01","SUNRISE" });
_myConn.PI_Service("_N_LOGIN_", new string[] { "SUNRISE" });
_myConn.PI_Service("_N_LOGOFF", new string[] { "" });
```


----------



## Hans54216 (28 Februar 2019)

KES_CK schrieb:


> Welchen ACX-File muss ich denn laden um die LUD's zu interpretieren?
> bzw. welchen Code muss ich verwenden:




```
SGUD = 0x36,
PGUD = 0x36,    //= SGUD
GUD1 = 0x36,    //= SGUD
LUD  = 0x18,
```



KES_CK schrieb:


> Dann habe ich noch ein weiteres Problem bei dem ich anscheinend noch Fehler mache.
> Ich bekomme keinen PI-Dienst gestartet. z.B. LOGIN oder LOGOUT bei meinen bisherigen Versuchen bekomme ich immer nur eine Exception.
> Hier meine Versuche:
> 
> ...




```
_myConn.PI_Service("_N_LOGIN_", new string[] { "001", "SUNRISE " });
_myConn.PI_Service("_N_LOGOUT", new string[] { "001" });
```


----------



## KES_CK (28 Februar 2019)

Super die PI-Kommandos klappen jetzt auch. 
Woher bekommt ich den mal so eine Info das als 1. Parameter "001" übergeben werden muss, kann ich das auch irgendwo selbst in Erfahrung bringen?

Dann nochmal die frage wegen des ACX-Files für die LUD's welchen muss ich da nehmen um an die aktuellen Lokal Variablen zu kommen?

Danke schon mal für die tolle Unterstützung!


----------



## Hans54216 (28 Februar 2019)

KES_CK schrieb:


> Super die PI-Kommandos klappen jetzt auch.
> Woher bekommt ich den mal so eine Info das als 1. Parameter "001" übergeben werden muss, kann ich das auch irgendwo selbst in Erfahrung bringen?


DocOnCD




KES_CK schrieb:


> Dann nochmal die frage wegen des ACX-Files für die LUD's welchen muss ich da nehmen um an die aktuellen Lokal Variablen zu kommen?


Siehe oben! (LUD  = 0x18)


----------



## KES_CK (28 Februar 2019)

In der DocOnCd habe ich mir das auch alles schon mehrfach angesehen.
Aber da steht auch nicht wie ich das Übergeben muss.
Auf der PLC Seite ist mit das schon klar. Aber das ich z.B. beim LOGOUT "001" übergeben muss und nicht nur "1" steht dort nirgends.


Das mit mit dem Bausteintyp (LUD = 0x18) verstehe ich schon. Aber wie komme ich an die Information welche
Lokal variablen gerade aktiv sind?


----------



## Hans54216 (28 Februar 2019)

KES_CK schrieb:


> In der DocOnCd habe ich mir das auch alles schon mehrfach angesehen.
> Aber da steht auch nicht wie ich das Übergeben muss.
> Auf der PLC Seite ist mit das schon klar. Aber das ich z.B. beim LOGOUT "001" übergeben muss und nicht nur "1" steht dort nirgends.
> Anhang anzeigen 44694



Ist immer eine 3-stellige Adresskennung aus BereichsID und Index.



KES_CK schrieb:


> Das mit mit dem Bausteintyp (LUD = 0x18) verstehe ich schon. Aber wie komme ich an die Information welche
> Lokal variablen gerade aktiv sind?
> Anhang anzeigen 44695



Die in der LUD Datei stehen sind aktiv. Analog zum HMI. Wenn du keinen Vorlaufstopp hast stehen hier eventuell die Variablen des Unterprogramms.


----------



## KES_CK (28 Februar 2019)

Hans54216 schrieb:


> Ist immer eine 3-stellige Adresskennung aus BereichsID und Index.



OK, das muss man halt wissen, danke.



Hans54216 schrieb:


> Die in der LUD Datei stehen sind aktiv. Analog zum HMI. Wenn du keinen Vorlaufstopp hast stehen hier eventuell die Variablen des Unterprogramms.


Genau das ist ja meine frage, in welcher Datei __N_??_???_ACX _stehen denn die aktuellen LUD's.
Wenn z.B. ein Unterprogramm mit Lokal variablen in einem M0 steht, kann ich mir das ja im Operate ansehen. Diese Liste mit den LUD's müsste ich ja abfragen können oder?


----------



## Thomas_v2.1 (28 Februar 2019)

Beim PI-Dienst _N_F_OPER scheint aber auch ein Fehler in der Doku zu sein. Laut Beschreibung besitzt dieser keine Parameter, aber meiner Meinung nach gibt es einen Parameter mit dem Dateinamen.


----------



## KES_CK (1 März 2019)

Thomas_v2.1 schrieb:


> Beim PI-Dienst _N_F_OPER scheint aber auch ein Fehler in der Doku zu sein. Laut Beschreibung besitzt dieser keine Parameter, aber meiner Meinung nach gibt es einen Parameter mit dem Dateinamen.



Vielleicht gucke ich ja auch immer an den falschen stellen aber in welcher Doku steht denn überhaupt was dazu? Ich finde den PI-Dienst "_N_F_OPER" weder in DocOnCd oder in der Doku vom Programmierpaket.


----------



## Hans54216 (1 März 2019)

KES_CK schrieb:


> OK, das muss man halt wissen, danke.


Oder richtige Doku lesen ;-)



KES_CK schrieb:


> Genau das ist ja meine frage, in welcher Datei __N_??_???_ACX _stehen denn die aktuellen LUD's.
> Wenn z.B. ein Unterprogramm mit Lokal variablen in einem M0 steht, kann ich mir das ja im Operate ansehen. Diese Liste mit den LUD's müsste ich ja abfragen können oder?


_N_CH1_LUD_ACX

M0 allein hält nur den Kanal aber nicht den Vorlauf an.

M0
Stopre

oder es sind sowieso schon Befehle verwendet die einen Vorlaufstopp auslösen. (z.B. Cancel, Wait...)

Um aber den richtigen Wert auszulesen ist der STOPRE zwingend (analog zu GUDs)


----------



## KES_CK (1 März 2019)

Hans54216 schrieb:


> Oder richtige Doku lesen ;-)



Die Doku will ich mal sehen wo das drin steht?  
Gib mir mal eine Tipp wo ich das finde, also in DocOnCd hab ich da keine weiteren Infos gefunden
oder steht eventuell in älteren ausgaben mehr?



Hans54216 schrieb:


> _N_CH1_LUD_ACX
> 
> M0 allein hält nur den Kanal aber nicht den Vorlauf an.
> 
> ...



Super jetzt klappt das mit den LUD's auch. Das mit dem Vorlaufstopp hab ich schon verstanden. Danke


----------



## Thomas_v2.1 (1 März 2019)

KES_CK schrieb:


> Vielleicht gucke ich ja auch immer an den falschen stellen aber in welcher Doku steht denn überhaupt was dazu? Ich finde den PI-Dienst "_N_F_OPER" weder in DocOnCd oder in der Doku vom Programmierpaket.



Wenn du z.B. das Sinumerik-Addon für WinCC flexible installiert hast, dann wird eine Dokumentation mitinstalliert in der auch die PI-Dienste beschrieben sind. Die Datei hat im Siemens-Forum mal jemand angehängt:
https://support.industry.siemens.com/tf/WW/en/posts/pi-services-parameters-information/106222


----------



## Hans54216 (1 März 2019)

Thomas_v2.1 schrieb:


> Beim PI-Dienst _N_F_OPER scheint aber auch ein Fehler in der Doku zu sein. Laut Beschreibung besitzt dieser keine Parameter, aber meiner Meinung nach gibt es einen Parameter mit dem Dateinamen.


In der Doku ist nicht nur einer drin ;-)

Ich hab diesen PI-Dienst jedoch noch nicht gesehen. Hab gerade ein bisschen mit gehört, es wird jedoch nur der "_N_F_OPEN" geschickt, auch wenn die Datei aktiv und somit geschützt ist.


----------



## KES_CK (1 März 2019)

Thomas_v2.1 schrieb:


> Wenn du z.B. das Sinumerik-Addon für WinCC flexible installiert hast, dann wird eine Dokumentation mitinstalliert in der auch die PI-Dienste beschrieben sind. Die Datei hat im Siemens-Forum mal jemand angehängt:
> https://support.industry.siemens.com/tf/WW/en/posts/pi-services-parameters-information/106222



Vielen Dank, sowas habe ich gesucht


----------



## Thomas_v2.1 (1 März 2019)

Hans54216 schrieb:


> Ich hab diesen PI-Dienst jedoch noch nicht gesehen. Hab gerade ein bisschen mit gehört, es wird jedoch nur der "_N_F_OPEN" geschickt, auch wenn die Datei aktiv und somit geschützt ist.



Ist ein einer deiner Aufzeichnungen vorhanden, in der aus diesem Thread:
https://www.sps-forum.de/hochsprachen-opc/87089-siemens-840dsl-alarme-auslesen-2.html#post655147

Was ist eigentlich an Dateien mit Acx so besonders? Bei anderen Dateitransfers ist ja der Dateiname ein String mit einem Newline am Ende. Aktuell suche ich einfach nach dem Newline und übernehme alles bis dahin als Dateiname. Bei Dateinamen mit Acx folgt dort aber direkt eine \0 und dann etliche weitere Werte bis dann auch irgendwann ein Newline kommt.


----------



## Hans54216 (1 März 2019)

Thomas_v2.1 schrieb:


> Was ist eigentlich an Dateien mit Acx so besonders? Bei anderen Dateitransfers ist ja der Dateiname ein String mit einem Newline am Ende. Aktuell suche ich einfach nach dem Newline und übernehme alles bis dahin als Dateiname. Bei Dateinamen mit Acx folgt dort aber direkt eine \0 und dann etliche weitere Werte bis dann auch irgendwann ein Newline kommt.



Wie schon mehrfach geschrieben sind die Acx keine normalen Dateien aus dem Dateisystem. Diese sind eher pseudo Dateien die die NC oder auch der Antrieb zum Übertragen von ganzen Paketen verwendet. Diese sind Binär codiert und speicher optimiert.

z.B. alle GUD Adressen aus einem Bereich

Daher auch kein PI-Dienst für den Upload


----------



## Hans54216 (25 April 2019)

Sagt euch das s7comm-plus Protokoll etwas? Ist das für TIA ohne PUT, GET Freigabe?

https://plc4x.apache.org/protocols/s7/s7comm-plus.html


----------



## DeltaMikeAir (25 April 2019)

Hans54216 schrieb:


> Sagt euch das s7comm-plus Protokoll etwas? Ist das für TIA ohne PUT, GET Freigabe?
> 
> https://plc4x.apache.org/protocols/s7/s7comm-plus.html



Ist auf jeden Fall interessant
https://www.blackhat.com/docs/eu-17...Break -The-Security-Wall-Of-S7CommPlus-wp.pdf


----------



## maxder2te (25 April 2019)

Hans54216 schrieb:


> Sagt euch das s7comm-plus Protokoll etwas? Ist das für TIA ohne PUT, GET Freigabe?
> 
> https://plc4x.apache.org/protocols/s7/s7comm-plus.html



Ein Artikel zu dem Thema:
https://www.heise.de/developer/meld...LC4X-ist-jetzt-Top-Level-Projekt-4404855.html


----------



## Thomas_v2.1 (26 April 2019)

Hans54216 schrieb:


> Sagt euch das s7comm-plus Protokoll etwas? Ist das für TIA ohne PUT, GET Freigabe?
> 
> https://plc4x.apache.org/protocols/s7/s7comm-plus.html



Das ist das Standard-Protokoll für die 1200/1500. Ich habe dafür auch einen Wireshark-Treiber der würde ich sagen zu 95% alles dekodiert was so möglich ist, den musst du aber in Form einer dll in den plugins Ordner von Wireshark packen:
https://sourceforge.net/projects/s7commwireshark/

An dem Apache PLC4X Projekt stört mich, dass es eine Java-Software sein soll. Für einen Treiber ist Java meiner Meinung nach die schlechteste Wahl, außer wenn man diese Software nur für sich selber benötigt. Eine Bibliothek mit C-Api ist das Mittel der Wahl, diese kann in so gut wie jeder anderen Sprache verwendet werden.


----------



## Jochen Kühner (28 April 2019)

Thomas_v2.1 schrieb:


> Das ist das Standard-Protokoll für die 1200/1500. Ich habe dafür auch einen Wireshark-Treiber der würde ich sagen zu 95% alles dekodiert was so möglich ist, den musst du aber in Form einer dll in den plugins Ordner von Wireshark packen:
> https://sourceforge.net/projects/s7commwireshark/.



Hy Thomas,

wie kannst du denn das meiste dekodieren wenn es verschlüsselt ist? Hast du denn das Protokoll irgendwo beschrieben?


----------



## Thomas_v2.1 (28 April 2019)

Jochen Kühner schrieb:


> wie kannst du denn das meiste dekodieren wenn es verschlüsselt ist? Hast du denn das Protokoll irgendwo beschrieben?


Es ist ja nicht verschlüsselt, außer evtl. einige wenige Objektdaten.
Du musst dich gegenüber der Steuerung nur authentifizieren, bei den ersten Versionen der 1200er vor Firmware Version 3 nicht einmal das.


----------



## Jochen Kühner (28 April 2019)

Das auslesen der Symbolinformationen aus der Steuerung, ist das auch schon verstanden?


----------



## Thomas_v2.1 (28 April 2019)

Im Prinzip ja, da gibt es aber mindestens 3 Möglichkeiten und Formate. Einmal für alle 1200er vor v3, dann für alles danach und 1500, und du kannst auch alles in einem Rutsch im xml-Format lesen.


----------



## Hans54216 (18 Juni 2019)

Hat schon jemand bei der S7-300 per LibNoDave Force Werte gesetzt/gelesen/gelöscht?

Ich hab mal ein paar Wireshark erstellt.

Anhang anzeigen PLC Force_20190618.rar


In der NoDave hab ich nur die "daveForce200" gefunden, was wohl für die 200er SPS steht.

Wie kann ich die pa, da, da2 und den Wireshark zusammenbringen? Bzw. was ist das im Wireshark (Header, Parameter, Data,...)


```
int DECL2 daveForce200(daveConnection * dc, int area, int start, int val) {
    int res;
    PDU p2;
    //    uc pa[]={0,1,18,4,17,67,2,0};
    //    uc da[]={'0','0'};


    //32,7,0,0,0,0,0,c,0,16,


    uc pa[] = { 0, 1, 18, 8, 18, 72, 14, 0, 0, 0, 0, 0 };
    uc da[] = { 0, 1, 0x10, 2,
        0, 1,
        0, 0,
        0,        // area
        0, 0, 0,        // start
    };
    uc da2[] = { 0, 4, 0, 8, 0, 0, };
    //    uc da2[]={0,4,0,8,7,0,};


    if ((area == daveAnaIn) || (area == daveAnaOut) /*|| (area==daveP)*/) {
        da[3] = 4;
        start *= 8;            /* bits */
    }
    else if ((area == daveTimer) || (area == daveCounter) || (area == daveTimer200) || (area == daveCounter200)) {
        da[3] = area;
    }
    else {
        start *= 8;
    }
    /*    else {
    if(isBit) {
    pa[3]=1;
    } else {
    start*=8;
    }
    }
    */
    da[8] = area;
    da[9] = start / 0x10000;
    da[10] = (start / 0x100) & 0xff;
    da[11] = start & 0xff;




    da2[4] = val % 0x100;
    da2[5] = val / 0x100;
    res = BuildAndSendPDU(dc, &p2, pa, sizeof(pa), da, sizeof(da), da2, sizeof(da2));
    return res;
}
```


----------



## Manuel_84 (18 Juni 2019)

Hallo euch allen!
Sorry das ich hier einfach so reinplatze, der Grund ist das mir dieser Thred im Forum bei meinem Problem schon eine Menge weiter geholfen hat und ich gehoft habe das ihr mir einen Tipp geben könntet. 
Ich schreibe gerade ein Programm das GUD Variablen und A_DBB Variablen einlesen muss. 
Mit der LibNoDave habe ich es bereits geschäft sämtliche GUDs+R Parameter +Maschinendaten auf einmal in einer Datei einzulesen.
Leider funktioniert das nicht mit A_DBB. Deshalb meine Frage, wie kann ich mit LibNoDave A_DBB lesen bzw. Schreiben? 

Danke für jede Hilfe! 

Schöne Grüße 

Manuel


----------



## Hans54216 (18 Juni 2019)

Hallo Manuel,

das funktioniert genau so wie die R-Parameter oder die Maschinendaten.
Mit dem NC-VAR-Selector musst du dir die ST_NC_VAR raussuchen und anschließend kannst du diese lesen/schreiben (je nach rechte der Variable).

In der Lib hab ich dafür die Klasse NC_Var hinzugefügt.

Beispiel für $A_DBB[0]
public static readonly NC_Var S_aDbb = new NC_Var(0x82, 0x1, 0x1E, 0x0, 0x7F, 0x1, 0x4, 0x2);


PS: Dass hab ich doch schon vor nen halben Jahr auf deine Frage an der Pinwand beantwortet.


----------



## Manuel_84 (18 Juni 2019)

Hallo Hans,

Ja danke dafür, aber ich brauche eine Möglichkeit ohne den NC Var Selector verwenden zu können. Weil es im verschiedene Projekte geht die das Programm automatisch einlesen können muss. Genauer geht es darum das man von einem Projekt eine spf öffnen kann und dann muss ich automatisch die darin enthaltenen a_dbb Variablen einlesen.


----------



## Hans54216 (18 Juni 2019)

Also noch einfacher kann ich es dir nicht machen.
Eine Variable "S_aDbb" des Types NC_Var in deinem Programm anlegen und je nach Adresse den Rot Markierten Wert ändern. (siehe oben)

S_aDbb.GetNckTag(0,0)


----------



## Manuel_84 (18 Juni 2019)

Oh okay, jetzt hab ichs verstanden, ich hatte das Nc Var Selector Programm nämlich nicht installiert, weil ich davon ausgegangen bin, dass man darin für ein bestimmtest Projekt die A_DBB Adressen raussuchen kann, aber das es je nach Anzahl der Variablen zu verschiedenen Adressen kommt. Aber wie es scheint ist der Nc Var Selektor projektunabhängig. Perfekt, vielen Dank für deine Hilfe. Das war genau das was ich gesucht hatte. 
Leider finde ich im Nc Var Selektor keine M und H Funktionen, kann man die Bits nur einlesen wenn man die DB Nummer kennt? Lässt sich die irgendwie rausbekommen?
Schöne Grüße 

Manuel


----------



## Thomas_v2.1 (18 Juni 2019)

Hans54216 schrieb:


> Hat schon jemand bei der S7-300 per LibNoDave Force Werte gesetzt/gelesen/gelöscht?



Die Force-Funktionen und diverse andere Test und Installationsfunktionen waren bisher in Wireshark nicht vollständig oder fehlerhaft.
In der Testversion die ich dir mal zur Verfügung gestellt habe, sind alle Funktionen integriert. D.h. alle die in SZL 0x131 Index 2 unter funkt_0, 1, 2 gemeldet werden.

Ich habe das bisher noch nicht im offiziellen Wireshark-Release veröffentlicht, weil ich recht umfangreiche Änderungen vorgenommen habe und ich keinen anderen Tester habe. Es gibt auch noch ein paar Parameter von denen ich nicht die genaue Bedeutung weiß und aktuell nur vermutete Funktionen stehen, weil da annähernd immer die gleichen Werte enthalten sind.

Die Force-Funktion ist etwas aufwändiger, weil das nicht nur eine Funktion ist sondern aus mehreren besteht. Jobs lesen, Job anlegen bzw. ersetzen, Force aktivieren, Jobs löschen. Und vorab am besten erstmal die SZL auslesen um zu sehen was die CPU überhaupt davon beherrscht.


----------



## Hans54216 (18 Juni 2019)

Währ top wenn du mir ne Basis für die Methoden hast. Testen plus Bug fix kann ich gern machen. Bei der PLC hab ich es meist mit ner 317 oder 319 zu tun.


----------



## Hans54216 (18 Juni 2019)

@Manuel: Der NC Var Selector ist ein Tool mit dem die Adressen der NC Variablen gesucht werden kann. Die Variablen sind abhängig von der NCK Version. Grundsätzlich löscht Siemens keine Variablen (Adressen). Bei Erweiterungen werden neue Bereiche hinzugefügt, alte funktionieren eigentlich lich immer weiter.

M und H Funktionen werden per FB2 mit den Kanal DB21... synchronisiert. Schau dir den UDT21 an.
M-Funktionen bis 100 hat Siemens bereits auskodiert. Die restlichen musst du über die allgemeine Schnittstelle für M-Funktionen (auch Kanal DB) selber auskodiert. 

Es gibt im NC Var Selector die M Funktionen, jedoch nur für einen IPO Takt. Also besser aus der PLC.


----------



## Manuel_84 (19 Juni 2019)

Danke für die Info, aber wie gesagt leider habe ich keine Möglichkeit in die Software einzugreifen, das Programm muss alles lesen können ohne das man dafür was anpassen kann.
Aber ich kann zumindest mal die ersten 100 M funktionen aus dem db21. Dbx194. 0+ holen und den Rest aus dem DB der bei dem Projekt verwenden wird. 
Dazu wollte ich ihn mir gerne über den Namen suchen, darum muss ich mir mal das Tool zum Projekt einlesen anschauen. Ausser dir fällt noch was weniger umständliches ein um den DB rauszubekommen...
Schöne Grüße 
Manuel


----------



## KES_CK (19 Juni 2019)

@Manuel: Da es sich bei den Hilfsfunktionen um Standard Signale aus der Nahtstellen zwischen NC und PLC handelt sind die DB's ja fest vom System vorgegeben.
DB21 => Kanal 1
DB22 => Kanal 2
- - -
DB30 => Kanal 10

Eine Beschreibung der Signale findest du z.B. in DocOnWeb / SINUMERIK 840D sl NC-Variable und Nahtstellensignale


----------



## Hans54216 (19 Juni 2019)

Wegen den Bits kannst du auch einfach wie oben beschrieben den UDT21 anschauen (gilt für alle Kanal DBs)


----------



## Manuel_84 (21 Juni 2019)

Hallo Hans, 
das mit dem NC Var Selektor klappt hervorragend. Du hattest gesagt das du einen Bereich für M-Funktionen kennst aber der nur einen IPO Takt geht. Wie heißt den der Bereich, leider finde ich ihn nicht und was meinst du mit einem Takt. Wenn man ihn öfter liest, wird er nicht mehr aktualisiert oder wie?
Nachdem mein Programm alle Variablen abdecken soll ist das jetzt ein extremer Aufwand für mich, nachdem ich gesehen habe wie viele Variablen es gibt im Var Selektor, darum versuche ich am Wochenende mal die Datenbank die hinter dem Programm steckt selbst zu verwenden und im DotNetLib eine Klasse zu machen mit der man dann eine Variable in die benötigten Daten umwandeln kann um sie auszulesen. Falls das klappt könntet ihr das ja eventuell zu eurer Bibliothek hinzufügen, dann braucht niemand mehr den Var Selektor zu verwenden, der ist ja echt ziemlich umständlich.
Ich finde darin auch keinen Bereich für selbstangelegte GUDs, weil ich die auch schreiben möchte. Das Auslesen über Datei ist ja super, aber damit kann man leider nicht schreiben. 
Habe übrigens probiert eine Schreibfunktion für die PlcNckVars dazu zu machen, das klappt gut. Warum fehlte eigentlich die Schreibfunktion?
In der Firma für die ich gerade arbeite, haben sie in der PLC ein Programm geschrieben, das der man eine GUD Variable angeben kann und aus dieser wird dann der Bereich und die anderen Daten gelesen, damit schreiben sie sie dann auch wieder. 
Gibt es in der LibNoDave eine Möglichkeit Gud zu schreiben?

Schöne Grüße

Manuel


----------



## Heinileini (21 Juni 2019)

Manuel_84 schrieb:


> das mit dem NC Var Selektor klappt hervorragend. Du hattest gesagt das du einen Bereich für M-Funktionen kennst aber der nur einen IPO Takt geht. Wie heißt den der Bereich, leider finde ich ihn nicht und was meinst du mit einem Takt.
> . . .
> Falls das klappt könntet ihr das ja eventuell zu eurer Bibliothek hinzufügen, dann braucht niemand mehr den Var Selektor zu verwenden, der ist ja echt ziemlich umständlich.
> Ich finde darin auch keinen Bereich für selbstangelegte GUDs, weil ich die auch schreiben möchte. Das Auslesen über Datei ist ja super, aber damit kann man leider nicht schreiben.
> Habe übrigens probiert eine Schreibfunktion für die PlcNckVars dazu zu machen, das klappt gut. Warum fehlte eigentlich die Schreibfunktion?


Moin Manuel!
Weisst Du, was eine NC ist?
Würdest Du für eine Maschine/Anlage ein NC- oder ein PLC-Programm schreiben und damit immens viel Verantwortung übernehmen wollen, wenn Du wüsstest, dass jeder dahergelaufene Abenteurer Deine Arbeit sabotieren und Menschenleben gefährden kann - ganz zu schweigen von Sachschäden anrichten?
Was sagen denn unsere SicherheitsExperten hier im Forum zu Deinem Ansinnen?

Gruss, Heinileini


----------



## Manuel_84 (21 Juni 2019)

Was ist denn das für eine Frage?!? Du weißt ja überhaupt nicht was ich vorhabe und redest irgend einen an den Haaren herbei gezogen Blödsinn über Sabotage!?!
Ja ich weiß was eine NC ist, weil ich selber seit 10 Jahren NC und seit 20 Jahren Hochsprachen programmiere. 
Aber wenn du es unbedingt willst willst was ich damit vorhabe. Es geht um ein Programm für NC Programmierer, weil jeder den ich kenne und auch ich selber nur mit einem Texteditor programmieren. Ohne Autocomplete, Folding, Syntaxcheck, Programme direkt hoch und runterladen, Zeilennummer automatisch generieren/einfügen, und vieles mehr was ich ZB. In Visual Studio gewohnt bin. Darum habe ich es auf mich genommen das zu ändern, weil ich genug Erfahrung mit NC habe und ein NC Studio in C++ programmieren kann um den NC Programmierern das Leben zu erleichtern. 
Weil man mit meinem Programm auch NC Programme Debuggen kann um Fehler zu suchen muss ich dazu natürlich vorher die Werte einlesen. 
Schöne Grüße 
Manuel


----------



## Heinileini (21 Juni 2019)

Ich wollte Dir durchaus ein weinig auf die Füsse treten, Manuel.

Wenn Dich der Begriff IPO-Takt schon in Verlegenheit bringt, kann ich nicht ahnen, dass sich dahinter 10 Jahre Erfahrung in NC-Programmierung verstecken.
Erfahrung in NC-Programmierung vielleicht, aber evtl. Null Erfahrung mit dem Arbeiten an einer NC-gesteuerten Maschine/Anlage?
Ich bezweifele, dass Du mehr als nur den NC-ProgrammQuellCode lesen musst, um den NC-Programmierern dass Leben zu erleichtern.
Für jede Maschine/Anlage noch eine individuelle Liste der definierten Funktionen, AchsLängen, Geschwindigkeiten, KollisionsBedingungen, u.s.w. . . .

Das Mitlesen der Schnittstelle zwischen der PLC und der NC in Echtzeit ist dafür m.E. absolut nicht erforderlich und das HerumSchreiben in dieser Schnittstelle mehr als gefährlich.
Wenn Du erfahren willst, welche BetriebsArtenGruppen, Kanäle, M-Funktionen, H-Funktionen, welche R-Parameter, welche Achsen u.s.w. bei einer Maschine/Anlage definiert sind und welche Bedeutung/Wirkung sie haben, dann lies die Doku der Maschine/Anlage. 

Durch das Studieren der Schnittstelle zwischen NC und PLC wirst Du einiges über die Komplexität der Maschine/Anlage erahnen können, aber nichts erfahren, das Dich in die Lage versetzt, Syntax- oder Plausibilitäts-Prüfungen oder ähnliches in einem NC-Programm-Editor zu realisieren.

Ganz offensichtlich haben 20 Jahre Erfahrung in HochsprachenProgrammierung Dich stärker geprägt, als 10 Jahre Erfahrung in NC-Programmierung.
Ich bin der letzte, der neue Ideen im Keim ersticken möchte - ganz im Gegenteil - aber ich fürchte, Du siehst vor lauter Bytes nicht mehr, wie leicht man vom entfernten Schreibtisch (oder unterwegs vom Handy) aus durch Umknippsen von einem oder mehreren Bits Tonnen von Material unkontrolliert in Bewegung setzen kann/könnte.
Ich bleibe deshalb ganz eisern bei meinem Einwand.

Wünsche Dir ein schönes WE - trotzdem, Heinileini

PS:
Du willst automatisch ZeilenNummern (sprich: SprungZiele) generieren/einfügen???
Sei auch damit bitte "übervorsichtig"!!! Du weisst, dass . . .
- es völlig "legal" ist, ein und dieselbe ZeilenNr in einem (Siemens-)NC-Programm mehrfach zu benutzen?
- dass u.a. die begrenzte Anzahl der zur Verfügung stehenden ZeilenNrn dazu zu verleiten kann, ganz absichtlich ZeilenNrn mehrfach zu vergeben?
- dass nicht nur aus "Performance-Gründen" die SprungBefehle unterscheiden, ob ab dem SprungBefehl oder ab ProgrammAnfang nach dem SprungZiel gesucht wird?
- dass man oft genug nicht nur sehenden Auges, sondern wohlüberlegt etlichen ProgrammZeilen keine ZeilenNr verpasst?


----------



## Peter Gedöns (21 Juni 2019)

ah Heinileini 
lass ihn mal machen, er wird dadurch eine Menge lernen.
Was er beschrieben hat gibt es ja schon als SINUTRAIN / oder die richtig teure Variante VirtualNCK.


----------



## Manuel_84 (21 Juni 2019)

Ja ich weiß vielleicht nicht was ein IPO Takt ist, wenn mich das in deinen Augen zu einem schlechteren Programmierer oder was auch immer macht, dann ist es halt so. Aber ich sehe wie umständlich und Zeit raubend NC programmieren in der Automations Branche ist. Wenn das Programm in einer Zeile mit 20 Variablen steht und man jede einzelne per Hand im Diagnose Fenster eingeben muss, Array Variablen mit anderen Variablen in der Klammer gar nicht mitgerechnet. Da kommt mir jedes Mal das Grausen wenn ich daran denke wie viele Leute seit Jahren so umständlich arbeiten müssen, wenn ich das mit Visual Studio vergleiche wo man sich jeden Wert jeder Variable jederzeit anschauen kann im dem man mit der Maus drüber fährt, dann braucht es niemanden wundern warum ich damit nicht gerne arbeite.
Mein Tool analysiert und evaluiert alle Variablen die im Programm verwendet werden, macht daraus eine Tabelle in der man alle Werte lesen und schreiben kann ohne vorher eine halbe Stunde lang Variablen rauszusuchen und einzutragen. Man kann damit auch auf einen Blick sehen warum es in einer Zeile steht weil alle Variablen bzw Bedingungen berechnet und farbig angezeigt werden damit man sofort sieht woran es liegt. Ist es zb eine M Funktion oder eine adbb Variable kann man automatisch mit einem Klick zum entsprechenden Netzwerk im PLC Programm springen.
Wegen der Zeilennummern, man muss sie ja nicht neu generieren und ob man eine oder mehrere einfügen will ist auch jedem selbst überlassen. Außerdem kann man einstellen in welchen Abständen und in welchem Format die Nummern wahlweise auch automatisch vorm Programm übertragen generiert werden. 
Wenn es fertig ist soll man einfach nur seine Programme testen können bevor man sie auf eine Maschine übertragt und dann erst feststellen muss, dass man irgendwo eine Klammer vergessen oder einen Denkfehler hatte oder man sich bei einer Variable verschrieben hat. Eben genau darum weil es gefährlich ist in Nc Programmen Fehler einzubauen. 
Wie gesagt es soll eine Hilfe und Erleichterung für Nc Programmierer sein. Nachdem ich selbst schon damit arbeite, weiß ich wie viel einfacher meine Arbeit damit geworden ist und noch werden wird.

Schöne Grüße 
Manuel


----------



## Heinileini (22 Juni 2019)

Manuel_84 schrieb:


> Da kommt mir jedes Mal das Grausen wenn ich daran denke wie viele Leute seit Jahren so umständlich arbeiten müssen, wenn ich das mit Visual Studio vergleiche wo man sich jeden Wert jeder Variable jederzeit anschauen kann im dem man mit der Maus drüber fährt, dann braucht es niemanden wundern warum ich damit nicht gerne arbeite.


Das kann ich sehr, sehr gut nachvollziehen, Manuel!
Das, was häufig als G-Code bezeichnet wird, kann man eigentlich nur verstehen und akzeptieren und lässt sich eigentlich nur dann erklären und verzeihen, wenn man an die Zeiten zurückdenkt, als die NC-Programme noch die Form eines zu einem Ring zusammengeklebten Lochstreifens hatten.
ProgrammSpeicher gab's noch nicht bzw. sie waren so winzig und teuer, dass man nicht lange überlegen musste, ob man lieber M00 oder M0 oder einfach nur M eintippt.
Aber Dein Bestreben mit der automatisierten ZeilenNummernVergabe erinnert mich ebenfalls an eine Zeitreise zurück zum Commodore PET.

Ja, diese Sprache ist für Hochsprachen-, Assemblersprachen- und auch PLC-Programmierer gleichermassen sehr gewöhnungs- aber auch sehr "entwöhnungsbedürftig" - keine Frage.
Darauf aufgesetzte Sprachen, wie z.B. "CL800", haben versucht, dem G-Code eine etwas freundlichere Maske aufzusetzen. Mit dem Erfolg, dass das Erstellen von NC-Programmen noch umständlicher, aufwendiger und praxisfremder wurde und man sich für das Testen der Programme dennoch auf die Ebene des G-Code begeben, sich also im EndEffekt mit 2 Programmiersprachen herumschlagen musste.
SimulationsMöglichkeiten bieten die Steuerungen normalerweise - schlimmstenfalls nur per "SatzVorlauf" mit Berechnung.

Du hast absolut Recht, dass man sich zahlreiche Verbesserungen und Arbeitserleichterungen einfallen lassen kann und einfallen lassen sollte.
Dass man aber beim Überstreichen z.B. einer M-Funktion mit dem Cursor automatisch ein "passendes" Netzwerk des PLC-Programms angezeigt bekommt, halte ich für schwachsinnig.
Derjenige, der in der PLC die M-Funktion programmiert hat und sie testen will, weiss, wo er nachsehen muss. Alle anderen interessiert es nicht und hat es auch nicht zu interessieren.
Wenn ich bei einem Taschenrechner die Taste für Quadratwurzel drücke, will ich auch nicht angezeigt bekommen, wie der ProgrammSchnipsel aussieht, der die Berechnung ausführen soll.
Wer vom NC-Programm aus in der PLC, sprich in einem Teil des BetriebsSystems der Maschine/Anlage herumbohrt, gehört erschossen. Maschinen-/Anlagen-Hersteller, die dies vom Anwender erwarten, ebenso.
Einerseits wird nach SicherheitsFunktionen und z.B. Kapselung geschrien und andererseits soll die Nahtstelle zwischen PLC und NC nicht nur freimütig gelesen, sondern auch beschrieben werden können?
Ich denke nicht, dass man überhaupt die Nahtstelle von aussen "sinnvoll" beschreiben und damit reproduzierbar irgendwelche sinnvollen Dinge bewirken kann.
Aber ein "sinnloses" Stochern an der Nahtstelle ist nicht harmloser. Die Nahtstelle ist sehr zeitkritisch und auch allerkleinste Störungen müssen unbedingt vermieden werden.
Ich sehe nach wie vor nicht, wie Dir diese Nahtstelle bei der Realisierung Deiner Funktionalitäten helfen soll oder könnte.
Eine Editor-ähnliche Einrichtung, einen ProgrammGenerator, eine Simulation (die nicht auf der NC läuft) kannst und musst Du ohne diese Realisieren.

Gruss, Heinileini

PS:
Wenn Du Excel statt eines TextEditors zum Erstellen/Pflegen/Analysieren von NC-Programmen verwendest, kannst Du damit schon einige Deiner Ideen umsetzen . . .


----------



## Hans54216 (22 Juni 2019)

Hallo Manuel,

du hast dir da auf jeden Fall eine Anspruchsvolle und zeitaufwändige Aufgabe ausgesucht, bei der du viel Über die Steuerung lernen kannst.

Wenn dir schon der IPO (Interpolation Takt) nichts sagt, wie sieht es dann mit Vorlauf/Hauptlauf, Alias (DEFINE AS), Endian (Byte Drehung zwischen PLC und NC) aus? 

Bei einem Editor, welcher die Definitionen der Maschine aufsammelt und einen einfachen Syntax-check durchführt, sowie bei online Verbindung durch mouse over den Wert der Variable (wie in der Ansicht für GUDs/LUDs oder Plc/Nc Variablen) anzeigt, wirst du noch erfolg haben. Dann wird es aber schon recht kompliziert.

1. s7comm ist nicht echtzeitfähig (Zyklus treu)
2. Vorlauf/Hauptlauf
3. DualPortRam: Dieser kann vom Maschinenhersteller selbst eingeteilt werden und von der NC per ($A_DBB, $A_DBD, $A_DBR) mit verschiedenen Datentypen beschrieben und gelesen werden (Auch per Bit Kodierung per B_AND und B_OR). In der PLC wird er per FC21 gelesen und beschrieben und dort kann wieder ein ganzer Bereich mit unterschiedlichen Datentypen beschrieben werden.
3. PLC: Du müsstest in Echtzeit das kompletten Programm simulieren um alle Eventualitäten (Sprünge,...) zu berücksichtigen, und das ohne Daten da diese nicht so schnell zur Verfügung stehen.




Manuel_84 schrieb:


> Hallo Hans,
> das mit dem NC Var Selektor klappt hervorragend. Du hattest gesagt das du einen Bereich für M-Funktionen kennst aber der nur einen IPO Takt geht. Wie heißt den der Bereich, leider finde ich ihn nicht und was meinst du mit einem Takt. Wenn man ihn öfter liest, wird er nicht mehr aktualisiert oder wie?



public static readonly NC_Var SSYNAC_Madr = new NC_Var(0x82, 0x40, 0xE, 0x0, 0x78, 0x1, 0x4, 0x2);
public static readonly NC_Var SSYNAC_Mval = new NC_Var(0x82, 0x40, 0x7, 0x0, 0x78, 0x1, 0x7, 0x4);

Auf der Variable steht für einen IPO Takt (1ms * Faktor -> bei uns typisch 2ms oder 4ms) der Wert. Da die NC pro IPO maximal einmal antwortet und das auch nur, wenn sie noch zeit hat ist das kein gangbarer Weg per s7comm. Nur der Trace erfasst die Daten mehr oder weniger sicher per IPO, dafür jedoch nur eine sehr begrenzte Anzahl.

Bei M-Funktionen musst du auch beachten, dass man diese unterschiedlich programmieren kann:

```
M60
M1=60

DEFINE M_ABC AS M60
DEFINE ABCD AS M1=60

M_ABC,
ABCD
```



Manuel_84 schrieb:


> Nachdem mein Programm alle Variablen abdecken soll ist das jetzt ein extremer Aufwand für mich, nachdem ich gesehen habe wie viele Variablen es gibt im Var Selektor, darum versuche ich am Wochenende mal die Datenbank die hinter dem Programm steckt selbst zu verwenden und im DotNetLib eine Klasse zu machen mit der man dann eine Variable in die benötigten Daten umwandeln kann um sie auszulesen. Falls das klappt köntet ihr das ja eventuell zu eurer Bibliothek hinzufügen, dann braucht niemand mehr den Var Selektor zu verwenden, der ist ja echt ziemlich umständlich.


Umständlich ja, aber enthält auch ne kleine Beschreibung sowie die Anomalien der Siemens Variablen welche mal 0 und mal 1 basiert sind.



Manuel_84 schrieb:


> Ich finde darin auch keinen Bereich für selbst angelegte GUDs, weil ich die auch schreiben möchte. Das Auslesen Über Datei ist ja super, aber damit kann man leider nicht schreiben.


Das hab ich zu einem früheren Zeitpunkt hier in diesem Beitrag schon erklärt wie das funktioniert.




Manuel_84 schrieb:


> Habe Übrigens probiert eine Schreibfunktion für die PlcNckVars dazu zu machen, das klappt gut. Warum fehlte eigentlich die Schreibfunktion?


Weiß nicht was du meinst. Die Schreibfunktion hab ich von Anfang an mit integriert.



Manuel_84 schrieb:


> In der Firma für die ich gerade arbeite, haben sie in der PLC ein Programm geschrieben, das der man eine GUD Variable angeben kann und aus dieser wird dann der Bereich und die anderen Daten gelesen, damit schreiben sie sie dann auch wieder.
> Gibt es in der LibNoDave eine Möglichkeit Gud zu schreiben?


Siemens liefert für die PLC den FB5 (lesen/schreiben von GUDs). Es wird sicher dieser verwendet und kein selbst programmierter.

LibNoDave ist rein senden und empfangen von S7comm. Wenn du also die Adresse der GUD weißt, kannst du diese lesen und auch beschreiben. Wie oben schon geschrieben hab ich das hier im Beitrag schon erklärt.


----------



## Manuel_84 (22 Juni 2019)

Lol, manchmal kommt es mir echt so vor als ob NC nicht viel mehr als ein erweiterter Lochstreifen ist.

Bei den M-Funktionen wird nicht das Netzwerk angezeigt sondern im Simatic Manager aufgemacht und dort hingesprungen. Natürlich nur wenn man das Projekt und den Manager hat. Die die ihn nicht haben brauchen ihn auch nicht die die ihn haben und sehen wollen warum das Nc Programm bei einer M-Funktion hängen bleibt können dann etwas weniger umständlich. Das ist alles.
Nach dem ich selbst gerade Dreh-, Fräsmaschinen und Schweißmaschinen mit kleinen Automationen Grund und Auto in Betrieb nehme, brauche ich das sogar relativ oft. Aber ich weiß was du meinst, die meisten Programmierer machen entweder NC oder PLC, nur die wenigsten beides. Aber für die Leute die damit nichts anzufangen wissen, verwenden es halt einfach nicht.


----------



## Manuel_84 (22 Juni 2019)

Hallo Hans,

hoffe das deine Quotes richtig angezeigt werden,...



			
				Hans54216 schrieb:
			
		

> Das hab ich zu einem früheren Zeitpunkt hier in diesem Beitrag schon erklärt wie das funktioniert.


Hättest du dazu villeicht einen Link?



			
				Hans54216 schrieb:
			
		

> Weiß nicht was du meinst. Die Schreibfunktion hab ich von Anfang an mit integriert.


Es gibt ein ReadValue(NC_Var) aber kein WriteValue(NC_Var, Value), habe später eh gesehen das es PlcNckVar abgeleitet von PlcVar gibt. Vielleicht liegt das an einer Inkompatibilität zwischen C++ und C#, aber ich konnte meine List<PlcNckVar> nicht an WriteValues übergeben. Musste da noch eine eigene Funktion dafür machen die dann in der Dll deine WriteValues Aufruft.



			
				Hans54216 schrieb:
			
		

> Bei M-Funktionen musst du auch beachten, dass man diese unterschiedlich programmieren kann


Danke für den Tipp, ich kannte zwar M=60 und M60 aber M1=60 hatte ich noch nie gesehen. Vermutlich für Kanal 1 M60. und das mit den DEFINES ist generell noch ein Thema das ich erst noch einbauen muss. Man kann das ja auch für R-Parameter und viele andere Sachen verwenden.

Ich habe nicht vor die PLC zu simulieren, das einzige wofür ich die PLC brauche ist um gewisse Variablen daraus zu lesen und in der Variablentabelle darauf zuzugreifen. Mein Programm soll aber im keine M-Funktionen an die PLC schicken und sie dazu bewegen irgendwelche Ausgänge zu setzen und womöglich irgendetwas dabei zerstören. Das wäre viel zu gefährlich.  Ausser man simuliert die PLC mit PLCSim dann wäre das zum Testen im Büro durchaus praktisch.
Ich muss nur wissen welche M-Funktionen auf True sind damit ich anzeigen kann wo das Programm hängt. 
Es soll so sein, das man zu einer Maschine kommt und sieht das sie irgendwo im Programm hängt. 
Dann macht man mein Tool auf, ließt alle verwendeten Parameter ein, setzt ggf. noch einen Parameter der an das Unterprogramm übergeben wurde (PROC).
jetzt kann mein Programm anzeigen wo die NC im Unterprogramm steht, welche Variablen welche Werte haben, welche Bedingungen erfüllt sind...
Neben bei hat man noch einen Ersatz für die Nc Diagnosetabelle und spart sich das mühsame und zeitraubende raussuchen der Variablen, wenn man dessen Werte sehen oder ändern möchte, kann man das dann ganz bequem machen.
Man könnte theoretisch wenn alles fertig ist NC Programme und Unterprogramme simulieren, aber wenn dann auch nur um sie zu testen, nicht um eine Nc in irgendeiner Art und Weise zu ersetzen. Es macht ja auch wenig Sinn. Wenn sich keine Achsen bewegen kommen bestimmte Eingänge nicht und das Programm würde früher oder später sowieso stehen bleiben. Nur um vielleicht zu sehen in Welcher Zeile welche Achse wo steht. Das kann man sich natürlich anzeigen lassen.
Es wird auch die Funktion geben M-Funktionen einfach zu ignorieren oder einen Brekpoint zu setzen wenn True den man dann manuell überspringen muss.
Man soll z.B eine Unterprogramm damit testen können das einem Werte errechnet und zurückgibt. Damit man im Büro bereits sehen kann das man sich nicht vertippt hat und sich alles gut überlegt hat. Dafür kann man das Programm dann auch Zeile für Zeile debuggen. Die Werte kann man sich einmal Online holen und später wieder Offline damit weiterarbeiten.
Also ist Echtzeit und PLC Simulieren, für mich nicht ausschlaggebend.

Schöne Grüße

Manuel


----------



## Hans54216 (22 Juni 2019)

Manuel_84 schrieb:


> Hättest du dazu villeicht einen Link?


Schau mal auf Seite 23 und 24.



Manuel_84 schrieb:


> Es gibt ein ReadValue(NC_Var) aber kein WriteValue(NC_Var, Value), habe später eh gesehen das es PlcNckVar abgeleitet von PlcVar gibt.


Die DotNet lib sowie LibNoDave sind ja für die PLC programmiert worden. Der PlcNckTag erbt vom PlcTag und dieser enthält auch die gemeinsamen Methoden. Die Klasse NC_Var hab ich für die bekannte Stuktur des NC-VAR-Selector (PLC FB2/FB3) hinzugefügten. Diese Klasse verwende ich eher um die Null Basierte Variable anzulegen und per GetNckTag() bekomme ich dann das exakte Ziel.



Manuel_84 schrieb:


> Danke für den Tipp, ich kannte zwar M=60 und M60 aber M1=60 hatte ich noch nie gesehen. Vermutlich für Kanal 1 M60. und das mit den DEFINES ist generell noch ein Thema das ich erst noch einbauen muss. Man kann das ja auch für R-Parameter und viele andere Sachen verwenden.


Siemens hat 5 Extention für die M-Funktionen. Diese können z.B. für die Spindeln verwendet werde. M1=3, M2=3
Das hat aber nichts mit dem Kanal zu tun. Für jeden Kanal hast du ja unabhängig voneinander die gesamte Pallette der M-Funktionen.

Du solltest dich in diesem Zusammenhang erst mal mit der PLC in Kombination mit der 840 befassen.

Auch ist es so, das die NC zwar die M-Funktion ausgibt und einen FB2 (entspricht normal OB1) Zyklus wartet ob die PLC eine Einlesesperre ausgibt, diese ist jedoch allgemein und hat nur bedingt mit der M-Funktion zu tun.
Sprich gibt die NC z.B. ein M7 (HDK ein) aus wird nicht diese die NC aufhalten, sondern die DB2 Einlesesperre im Kühlmittelbaustein welcher durch die M7 gestartet wird.


----------



## Hans54216 (22 Juni 2019)

Manuel_84 schrieb:


> Ich muss nur wissen welche M-Funktionen auf True sind damit ich anzeigen kann wo das Programm hängt.
> Es soll so sein, das man zu einer Maschine kommt und sieht das sie irgendwo im Programm hängt.
> Dann macht man mein Tool auf, ließt alle verwendeten Parameter ein, setzt ggf. noch einen Parameter der an das Unterprogramm übergeben wurde (PROC).
> jetzt kann mein Programm anzeigen wo die NC im Unterprogramm steht, welche Variablen welche Werte haben, welche Bedingungen erfüllt sind...
> Neben bei hat man noch einen Ersatz für die Nc Diagnosetabelle und spart sich das mühsame und zeitraubende raussuchen der Variablen, wenn man dessen Werte sehen oder ändern möchte, kann man das dann ganz bequem machen.



Durch die Variable ActBlock siehst du wo der Programmzeiger gerade steht. (Aktueller NC Satz)
Bei den Variablen kommt der Vorlauf ins Spiel. Diese zeigen teilweise schon Werte an, welche sie erst in der Zukunft besitzen, aber diurch den Kode im Vorlauf bestimmt ist.

Es gibt Variablen welche im Vorlauf und welche im Hauptlauf gelesen und beschrieben werden. Wenn du Zeitkritisch oder G64 programmierst solltest du das auch im G-Kode beachten. Zu dem Thema gehört auch daß STOPRE.


----------



## Manuel_84 (23 Juni 2019)

Danke das mit dem ActBlock kann ich sehr gut gebrauchen.
Mit dem Vorlauf und Hauptlauf hatte ich auch schon ein paar mal was zu tun, wie jeder wahrscheinlich, wenn das Programm nicht das tut was man will. Da hilft oft STOPRE um den Vorlauf zu stoppen. 
Wie und ob ich das in meinem Programm berücksichtigen kann muss ich mir noch überlegen. Ich könnte schon immer 5 Zeilen im voraus lesen außer es kommt STOPRE, aber ob das beim Fehlersuchen hilfreich sein würde oder die Leute nur verwirren würde ist schwer zu sagen.
Vielleicht mach ich das optional. 

Habe mir heute nochmal eure ganze Unterhaltung durchgelesen. Soweit ich das gesehen habe ist auf Seite 24 das erste mal davon geredet Adressen von Guds aus der gud acx zu bestimmen.
Auf Seite 37 bedankt sich KES_CK bei dir für das super Code snippet zum interpretieren von acx.
Leider konnte ich das snippet weder im Forum noch in der Bibliothek finden. 
Habt ihr das schon eingebunden?

SG Manuel


----------



## Hans54216 (24 Juni 2019)

Manuel_84 schrieb:


> Mit dem Vorlauf und Hauptlauf hatte ich auch schon ein paar mal was zu tun, wie jeder wahrscheinlich, wenn das Programm nicht das tut was man will. Da hilft oft STOPRE um den Vorlauf zu stoppen.
> Wie und ob ich das in meinem Programm berücksichtigen kann muss ich mir noch überlegen. Ich könnte schon immer 5 Zeilen im voraus lesen außer es kommt STOPRE, aber ob das beim Fehlersuchen hilfreich sein würde oder die Leute nur verwirren würde ist schwer zu sagen.
> Vielleicht mach ich das optional.


Du brauchst keine Zeilen im Vorlauf lesen, sondern die NC macht das und wenn keine Einlesesperre oder STOPRE für deinen Satz hast, zeigst du eventuell die faschen Werte an.
Dafür müsstest du in so einem Fall den Vorlauf selber zurück rechnen.








Manuel_84 schrieb:


> Habe mir heute nochmal eure ganze Unterhaltung durchgelesen. Soweit ich das gesehen habe ist auf Seite 24 das erste mal davon geredet Adressen von Guds aus der gud acx zu bestimmen.
> Auf Seite 37 bedankt sich KES_CK bei dir für das super Code snippet zum interpretieren von acx.
> Leider konnte ich das snippet weder im Forum noch in der Bibliothek finden.



Seite 24:
DotNetSiemensPLCToolBoxLibrary (LibNoDave) Zugriff auf Dual-Port RAM / FB15


----------



## Manuel_84 (24 Juni 2019)

Hallo Hans,
das Programm auf der Seite kenn ich, ich dachte das ihr daran inzwischen noch was gemacht hattet. Alles klar.


----------



## KES_CK (4 September 2019)

Gibt es eigentlich auch eine Möglichkeit per DotNetSiemensPLCToolBoxLibrary ein NC / PLC Archiv zu machen? bzw. hat sich schon jemand mit den Thema beschäftigt?


----------



## Thomas_v2.1 (5 September 2019)

Mit welcher Software erstellst du denn üblicherweise so ein Archiv, und wo läuft diese?
Wenn die Daten über Netzwerk ausgelesen werden, dann erstellst du am besten mit Wireshark eine Aufzeichnung davon, und dann kann man sehen ob und wie man dieses nachbilden kann.


----------



## KES_CK (5 September 2019)

Thomas_v2.1 schrieb:


> Mit welcher Software erstellst du denn üblicherweise so ein Archiv, und wo läuft diese?
> Wenn die Daten über Netzwerk ausgelesen werden, dann erstellst du am besten mit Wireshark eine Aufzeichnung davon, und dann kann man sehen ob und wie man dieses nachbilden kann.



Hallo Thomas,
die Archive werden üblicherweise mit der Software der Bedienoberfläche (Sinumerik Operate) erzeugt. Ich habe die Software auch bei mir auf dem Laptop und
habe von Beiden Varianten eine Aufzeichnung gemacht.
Die Capture-Files sind aber relativ groß (>25MB) und bekomme ich nicht hochgeladen. Kann ich Dir das auch irgendwie anders zukommen lassen?

Gruß Christian


----------



## Hans54216 (5 September 2019)

Das Archiv ist ja im ACX Format, was einem Siemens Binärformat entspricht. Somit bringt dir der Wireshark recht wenig.

Archiv erstellen läuft in der HMI. Du kannst zwar noch aufzeichnen welche Daten alles angefordert werden, das siehst du aber auch wenn du das Archiv öffnest (Siemens Tool oder Notepad).
Entscheidend ist wie du die Dateien verschachtelst. Ich hab mir das mal angesehen, es aber dann sein lassen und auf die fertige Siemens Lösung gesetzt.


----------



## Hans54216 (5 September 2019)

KES_CK schrieb:


> Hallo Thomas,
> Die Capture-Files sind aber relativ groß (>25MB) und bekomme ich nicht hochgeladen. Kann ich Dir das auch irgendwie anders zukommen lassen?


Per 7z zippen


----------



## KES_CK (5 September 2019)

Hans54216 schrieb:


> Per 7z zippen


War auch mein erster Gedanke, wird aber nur minimal kleiner.



Hans54216 schrieb:


> Das Archiv ist ja im ACX Format, was einem Siemens Binärformat entspricht. Somit bringt dir der Wireshark recht wenig.
> 
> Archiv erstellen läuft in der HMI. Du kannst zwar noch aufzeichnen welche Daten alles angefordert werden, das siehst du aber auch wenn du das Archiv öffnest (Siemens Tool oder Notepad).
> Entscheidend ist wie du die Dateien verschachtelst. Ich hab mir das mal angesehen, es aber dann sein lassen und auf die fertige Siemens Lösung gesetzt.


Wenn ich mir die Captures anschaue sieht es so aus als wenn erst eine Datei mit einer einer Liste des jeweiligen Bereichs angefordert wird und dann jede Datei einzeln hochgeladen wird.
Ist vermutlich zu aufwendig, da was selber zu machen und vor allen dingen je nach NC-Softwarestand noch Anpassungen zu machen.

Gruß Christian


----------



## Thomas_v2.1 (5 September 2019)

Deine Logfiles sind so groß weil dort noch eine SSH-Session mit aufgezeichnet wurde. Vermutlich gehören diese Daten aber nicht mit zur Sicherung.
Wenn du in der Filterzeile tcp.port == 102 eingibst, dann hast du nur die Kommunikation über den TCP-Port 102, über den hier vermutlich vollständig die Sicherung abgewickelt wird.
Wenn du dann wählst "Spezielle Pakete exportieren" und dann nur Displayed anwählst, dann ist die Datei nur noch 1MB groß (gezippt unter 200 kB).

Ich würde sagen, dass prinzipiell alle Funktionen die ich dort sehe auch in der Bibliothek vorhanden sind, für die S7 Bausteine sowieso, für den NC Teil müsste man sehen woher die ganzen Dateinamen stammen die dort ausgelesen werden. Soweit ich weiß lassen sich ja auch Verzeichnisinhalte auslesen an denen man sich dann entlang hangeln könnte. So funktioniert es beim SPS Teil ja auch, es wird erst eine Bausteinliste abgefragt und dann die jeweiligen vorhandenen Bausteine heruntergeladen.


----------



## Hans54216 (5 September 2019)

Thomas_v2.1 schrieb:


> Ich würde sagen, dass prinzipiell alle Funktionen die ich dort sehe auch in der Bibliothek vorhanden sind, für die S7 Bausteine sowieso, für den NC Teil müsste man sehen woher die ganzen Dateinamen stammen die dort ausgelesen werden. Soweit ich weiß lassen sich ja auch Verzeichnisinhalte auslesen an denen man sich dann entlang hangeln könnte. So funktioniert es beim SPS Teil ja auch, es wird erst eine Bausteinliste abgefragt und dann die jeweiligen vorhandenen Bausteine heruntergeladen.



Wie oben geschrieben funktioniert das reine laden/lesen der Dateien noch recht einfach. Um alle Dateien zu sichern musst du zunächst einen Leseauftrag auf den Hauptordner machen, welcher immer Vorhanden ist. Als Antwort bekommt du ein File welches die Dateien/Ordner direkt unter dem Ordner enthält. Dann gehst du halt alle Ordner durch bis diese keine weiteren enthalten.

Die Schwierigkeit ist dann aber das ganze als Archiv zu verpacken. Wie geschrieben handelt es sich um ein Binär Format welches schon einen erhöhten Aufwand zur folge hat um die Füllbytes und Checksummen raus zu finden. Ich hab das mal für die GUDs gemacht.

Das Binär Archiv ist sowie so nicht zukunftsweisend, da Siemens mit der Evo Line/One auf ein Zip File setzt. Dann wird es recht einfach, da dieses mit den zipper öffnen und packen kannst.


----------



## Thomas_v2.1 (5 September 2019)

Und wie wird dieses ACX-Archiv bei Bedarf wiederhergestellt? Wird es als eine Datei auf die Steuerung geladen und dort entpackt, oder extern entpackt und dann alles wieder in Einzelteilen hochgeladen?


----------



## Hans54216 (5 September 2019)

Thomas_v2.1 schrieb:


> Und wie wird dieses ACX-Archiv bei Bedarf wiederhergestellt? Wird es als eine Datei auf die Steuerung geladen und dort entpackt, oder extern entpackt und dann alles wieder in Einzelteilen hochgeladen?



Das Archiv wird vom HMI erstellt und auf der CF-Karte (Linux) oder Festplatte (Windows) abgelegt und kann bei bedarf von selbigen wieder eingespielt werden.

Es ist auch möglich das Archiv offline per Siemens Tool (Create MyConfig) zu öffnen und Dateien auszutauschen. Das Archiv besteht immer aus einem Packet. Dieses kann nur die NC, PLC, Antriebe (DP) enthalten oder auch alles zusammen.


----------



## LowLevelMahn (2 Oktober 2019)

Gibt es schon eine Format-Beschreibung zu den ACX-Dateien, es scheint ja verschiedene Varianten zu geben - die GUD ACX die ich so angeschaue haben alle einen 0x56 byte header aber es gibt auch andere ACX-Dateien, in Operate-Temp-Ordnern die auch die "Acx" Signatur haben aber einen großeren Header haben und glaube ich einen anderen Aufbau, gibt es eine möglichkeit zu erkennen ob es eine GUD-ACX ist?


```
Beispiel: CH1_GD2.ACX


00000000  41 63 58 00 00 02 00 00 C3 00 00 02 00 00 00 BC  AcX.....Ã......¼
00000010  0C 05 02 00 00 00 3D 65 05 17 64 05 14 63 05 02  ......=e..d..c..
00000020  47 25 00 00 02 48 25 A8 00 02 49 25 11 00 02 4A  G%...H%¨..I%...J
00000030  25 7F 00 20 66 65 62 64 30 38 63 38 34 39 39 38  %.. febd08c84998
00000040  66 39 35 35 38 38 61 33 63 64 63 31 64 39 33 34  f95588a3cdc1d934
00000050  35 62 30 38 37 37 A2 0D 04 00 00 00 00 0A 9B 60  5b0877¢.......›`
00000060  58 5F 42 41 43 4B 4C 41 53 48 02 88 20 01 00 01  X_BACKLASH.ˆ ...
00000070  89 20 0A 01 19 24 02 01 07 24 07 01 08 24 04 A4  ‰ ...$...$...$.¤
00000080  0D 04 00 00 00 00 0C 9B 60 58 5F 32 5F 42 41 43  .......›`X_2_BAC
00000090  4B 4C 41 53 48 02 88 20 02 00 01 89 20 0A 01 19  KLASH.ˆ ...‰ ...
000000A0  24 02 01 07 24 07 01 08 24 04 A2 0D 04 00 00 00  $...$...$.¢.....
000000B0  00 0A 9B 60 59 5F 42 41 43 4B 4C 41 53 48 02 88  ..›`Y_BACKLASH.ˆ
000000C0  20 03 00 01 89 20 0A 01 19 24 02 01 07 24 07 01   ...‰ ...$...$..
000000D0  08 24 04 A4 0D 04 00 00 00 00 0C 9B 60 59 5F 32  .$.¤.......›`Y_2
000000E0  5F 42 41 43 4B 4C 41 53 48 02 88 20 04 00 01 89  _BACKLASH.ˆ ...‰
000000F0  20 0A 01 19 24 02 01 07 24 07 01 08 24 04 A2 0D   ...$...$...$.¢.
00000100  04 00 00 00 00 0A 9B 60 5A 5F 42 41 43 4B 4C 41  ......›`Z_BACKLA
00000110  53 48 02 88 20 05 00 01 89 20 0A 01 19 24 02 01  SH.ˆ ...‰ ...$..
00000120  07 24 07 01 08 24 04 A4 0D 04 00 00 00 00 0C 9B  .$...$.¤.......›
00000130  60 5A 5F 32 5F 42 41 43 4B 4C 41 53 48 02 88 20  `Z_2_BACKLASH.ˆ 
00000140  06 00 01 89 20 0A 01 19 24 02 01 07 24 07 01 08  ...‰ ...$...$...
00000150  24 04                                            $.


davon ist der header: size = 0x56


Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F


00000000  41 63 58 00 00 02 00 00 C3 00 00 02 00 00 00 BC  AcX.....Ã......¼
00000010  0C 05 02 00 00 00 3D 65 05 17 64 05 14 63 05 02  ......=e..d..c..
00000020  47 25 00 00 02 48 25 A8 00 02 49 25 11 00 02 4A  G%...H%¨..I%...J
00000030  25 7F 00 20 66 65 62 64 30 38 63 38 34 39 39 38  %.. febd08c84998 <-- "febd08c84998f95588a3cdc1d934" sieht ein bisschen nach MD5 aus
00000040  66 39 35 35 38 38 61 33 63 64 63 31 64 39 33 34  f95588a3cdc1d934
00000050  35 62 30 38 37 37                                5b0877


und die variablen sind:


                     strlen   (str                                 )         nr
A2 0D 04 00 00 00 00 0A 9B 60  58 5F 42 41 43 4B 4C 41 53 48        02 88 20 01 00 01 89 20 0A 01 19 24 02 01 07 24 07 01 08 24 04
A4 0D 04 00 00 00 00 0C 9B 60  58 5F 32 5F 42 41 43 4B 4C 41 53 48  02 88 20 02 00 01 89 20 0A 01 19 24 02 01 07 24 07 01 08 24 04
A2 0D 04 00 00 00 00 0A 9B 60  59 5F 42 41 43 4B 4C 41 53 48        02 88 20 03 00 01 89 20 0A 01 19 24 02 01 07 24 07 01 08 24 04
A4 0D 04 00 00 00 00 0C 9B 60  59 5F 32 5F 42 41 43 4B 4C 41 53 48  02 88 20 04 00 01 89 20 0A 01 19 24 02 01 07 24 07 01 08 24 04
A2 0D 04 00 00 00 00 0A 9B 60  5A 5F 42 41 43 4B 4C 41 53 48        02 88 20 05 00 01 89 20 0A 01 19 24 02 01 07 24 07 01 08 24 04
A4 0D 04 00 00 00 00 0C 9B 60  5A 5F 32 5F 42 41 43 4B 4C 41 53 48  02 88 20 06 00 01 89 20 0A 01 19 24 02 01 07 24 07 01 08 24 04


aber auch eine bi000005.acx (aus einem Operate temp ordern)


00000000  41 63 58 00 00 02 00 00 74 00 00(23)01 60 76 65  AcX.....t..#.`ve  <--- 0x23 Zeichen fuer ["version="1.0" encoding="ISO-8859-1"]
00000010  72 73 69 6F 6E 3D 22 31 2E 30 22 20 65 6E 63 6F  rsion="1.0" enco
00000020  64 69 6E 67 3D 22 49 53 4F 2D 38 38 35 39 2D 31  ding="ISO-8859-1
00000030  22 28 7A 08 25 92 00 04 11 20 24 2A 43 00(16)8E  "(z.%’... $*C..Ž  <--- 0x16 Zeichen fuer [SINAMICS Postprocessor]
00000040  60 53 49 4E 41 4D 49 43 53 20 50 6F 73 74 70 72  `SINAMICS Postpr
00000050  6F 63 65 73 73 6F 72 02 38 48 05 00(20)06 60 61  ocessor.8H.. .`a  <--- 0x20 Zeichen fuer [a838ce45e66e63dc54c24d8d59752b1f] MD5?
00000060  38 33 38 63 65 34 35 65 36 36 65 36 33 64 63 35  838ce45e66e63dc5
00000070  34 63 32 34 64 38 64 35 39 37 35 32 62 31 66     4c24d8d59752b1f
--> keine weiteren Daten
```

gibt es schon mehr Infos?


----------



## Hans54216 (25 Oktober 2019)

Ich versuche gerade das ganze mit .Net Core auf Linux (Ubuntu 18.04.3 LTS x64) zum laufen zu bringen. Compilieren hat noch funktioniert, jedoch crasht die Anwendung beim Verbindungsaufbau.

Speicherzugriffsfehler (Speicherabzug geschrieben)

Package: dotnet-host 3.0.0-1
Title:       dotnet crashed with SIGSEGV in daveNewInterface()


testISO_TCP scheint sich zu verbinden, jedoch bricht der NC Programm Upload oder bereits der PI-Service ab und bringt nen Fehler.

Update: Lesen eines DB Bytes hat mit der testISO_TCP funktioniert.
Kompilieren scheint nicht das Problem zu sein.


----------



## Jochen Kühner (25 Oktober 2019)

ja hast du denn libnodave für linux compiliert?
ich hatte libnodave in verbindung mit meiner bibliothek vor jahren auf einem iphone benutzt, also es sollte zumindest theoretisch funktionieren.


----------



## Hans54216 (25 Oktober 2019)

Jochen Kühner schrieb:


> ja hast du denn libnodave für linux compiliert?
> ich hatte libnodave in verbindung mit meiner bibliothek vor jahren auf einem iphone benutzt, also es sollte zumindest theoretisch funktionieren.



Hab ja geschrieben, dass ich die testISO_TCP zusammen mit der lib erfolgreich kompiliert habe und das Testprogram auch funktioniert.

Hab die Lib auch schon auf Linux für Raspi und yocto linux kompiliert und erfolgreich ausgeführt. Jedoch bis jetzt mit Mono. 

Nach dem alle von .Net Core reden wollt ich das jetzt auch mal angehen.

.Net Standard + Core ist aber der letzte Dreck.
Gedanke top, Umsetzung mangelhaft. Reine  Bastelsoftware.


----------



## Jochen Kühner (26 Oktober 2019)

d.h. die gleiche dll läuft mit mono? kann es ein 32/64 bit problem sein?


----------



## Hans54216 (26 Oktober 2019)

Hab auf der vm extra kein Mono installiert um nur den dotnet Part zu testen. Ist aber mein nächster Schritt, jedoch erst Dienstag.
Ubuntu ist x64, dotnet ruft auch die x64 dll auf und ein kompiliertes Hallo Welt in c sagt auch x64.
Mit falscher IP kommt kein Crash,  sondern lediglich der timeout.


----------



## Thomas_v2.1 (26 Oktober 2019)

Hast du die Aufrufe mal aus einem C-Programm heraus getestet?

Wenn die Aufrufe aus einem C-Programm heraus funktionieren, muss es ja am Glue-Code zu Mono liegen.
Die PI-Funktionen oder die NC-Upload verwendet ja strings, könnte evtl. eine Unicode Geschichte sein.
Oder da ist was bei der Umsetzung der const Parameter nicht korrekt. Bei davePIstart_nc z.B. habe ich einige Zeiger-Parameter als const deklariert die in den Funktionen ausschließlich gelesen werden.


----------



## Jochen Kühner (26 Oktober 2019)

Kann es denn ein Problem sein das ich den Socket nicht in C sondern in C# öffne? Vlt. gibts da mit NetCore Probleme?


----------



## Hans54216 (29 Oktober 2019)

---------------------------------------


----------



## Hans54216 (30 Oktober 2019)

.........................................................


----------



## Hans54216 (30 Oktober 2019)

Hab den Crash noch weiter eingekränzt.

Problem ist die Struktur mit den beiden Pointern.


```
public struct daveOSserialType        {
            public volatile IntPtr rfd;
            public volatile IntPtr wfd;
        }
```

nodave.h


```
#ifdef LINUX
#define DECL2
#define EXPORTSPEC
    typedef struct dost {
        int rfd;
        int wfd;
        //    int connectionType;
    } _daveOSserialType;
#include <stdlib.h>
#define tmotype int
#define OS_KNOWN    // get rid of nested ifdefs.
#endif    


#ifdef BCCWIN
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#define DECL2 __stdcall
#define tmotype int


#ifdef DOEXPORT
#define EXPORTSPEC __declspec (dllexport) 
#else
#define EXPORTSPEC __declspec (dllimport) 
#endif


    typedef struct dost {
        HANDLE rfd;
        HANDLE wfd;
        //    int connectionType;
    } _daveOSserialType;


#define OS_KNOWN
#endif
```


----------



## Hans54216 (30 Oktober 2019)

sizeof(int) => 4
sizeof(IntPtr) => 8

Wird für Windows wirklich der HANDLE benötigt oder funktioniert hier auch int? In der "libnodave.net.cs" von "libnodave-0.8.5" wird int verwendet, obwohl nodave.h gleich ist.


----------



## PN/DP (30 Oktober 2019)

Hans54216 schrieb:


> Hab den Crash noch weiter eingekränzt.
> 
> Problem ist die Struktur mit den beiden Pointern.
> 
> ...


Schade, daß Du nun einige Beiträge von Dir gelöscht hast... stand da nicht was von 64 Bit?

Ich hatte mit Exel64 VBA das Problem, daß daveNewInterface(..) crasht. Das Problem habe ich so gelöst bekommen, daß ich davePascalNewInterface(..) verwendet habe.

Harald


----------



## Hans54216 (30 Oktober 2019)

PN/DP schrieb:


> Schade, daß Du nun einige Beiträge von Dir gelöscht hast... stand da nicht was von 64 Bit?
> 
> Ich hatte mit Exel64 VBA das Problem, daß daveNewInterface(..) crasht. Das Problem habe ich so gelöst bekommen, daß ich davePascalNewInterface(..) verwendet habe.
> 
> Harald


Hallo PN/DP ich hab nur die unnötigen Beiträge gelöscht. Die wichtigen z.B. #453 hab ich so gelassen.
Dort siehst du den Header (nodave.h welcher unterschiedlich ist zwischen Linux (int) und Windows (pointer) ist) und den Aufruf in C#


----------



## Jochen Kühner (30 Oktober 2019)

Bei manchen Windows funktion wird in der WInapi auch Handle verwendet, das ist dann 64Bit, das würde dann probleme machen wenn du das auf 32 bit änderst.
Es läuft ja auch unter windoes mit 64 bit.

Man muss nun rausfinden ob unter 64bit linux die Übergabeparameter 64 oder 32 bit sind für die Handles und das dann anpassen...


----------



## Jochen Kühner (30 Oktober 2019)

Hans54216 schrieb:


> sizeof(int) => 4
> sizeof(IntPtr) => 8
> 
> Wird für Windows wirklich der HANDLE benötigt oder funktioniert hier auch int? In der "libnodave.net.cs" von "libnodave-0.8.5" wird int verwendet, obwohl nodave.h gleich ist.



glaube ich hab das mal im zuge von 64bit angepasst...
aber vtl reicht ja unter 64 bit linux trotzdem 32bit. dann kannst du ja die dll imports für linux anpassen.


----------



## Hans54216 (30 Oktober 2019)

Jochen Kühner schrieb:


> glaube ich hab das mal im zuge von 64bit angepasst...
> aber vtl reicht ja unter 64 bit linux trotzdem 32bit. dann kannst du ja die dll imports für linux anpassen.


Ich hab jetzt mal in der NoDave.h auch für BCCWIN int anstelle von HANDLE geschrieben und dann in C# von IntPtr zu int.

Funktioniert mit Win32, Win64, Linux64.
(ISO over TCP IP)

"int" ist in C# und C Int32.
IntPtr (void*) ist entweder 32 oder 64 Bit


----------



## Hans54216 (30 Oktober 2019)

Thomas_v2.1 schrieb:


> Im Prinzip ja, da gibt es aber mindestens 3 Möglichkeiten und Formate. Einmal für alle 1200er vor v3, dann für alles danach und 1500, und du kannst auch alles in einem Rutsch im xml-Format lesen.


Hallo Thomas,
du hast geschrieben, dass du einen S7CommPlus Treiber für Wireshark geschrieben hast.
Nach dem die neue 840d Evoline auch mit ner 1500 SPS kommt wird das langsam interessant. Wie schätzt du den Aufwand ein das ganze in NoDave einzubauen?


----------



## Thomas_v2.1 (30 Oktober 2019)

In den Code von libnodave würde ich das definitiv niemals einbinden, das ist als Basis nicht mehr zeitgemäß. Ich habe einen ganz rudimentären Treiber für die ganz alte Version der 1200er, dort wird keine Authentifizierung benötigt, damit kann ich den Variablenhaushalt browsen und dann Werte lesen. Im Wireshark Plugin für das neue Protkoll wird weitestgehend alles angezeigt was dort abläuft, um einen Treiber zu schreiben kann man das aber nur als Anhaltspunkt nehmen.
Das Problem ist m.M.n. eher ein rechtliches als ein technisches, weil dort einige kryptografische Funktionen verwendet werden, von denen du a) wissen musst wie sie funktionieren und b) du ein paar Schlüssel dazu besitzen musst. a) ist seit kurzem von anderer Stelle öffentlich dokumentiert worden, da könnte man sich darauf berufen. Zu b) also Closed-Source Produkte welche das Protokoll unterstützen geben sich Mühe das gut in ihrem Code zu verstecken.


----------



## Jochen Kühner (30 Oktober 2019)

@thomas_v2.1 gabs hier nicht mal ein link zu einer gruppe die nen java tia treiber entwickeln wollten, und auch ein bisschen übers protokoll geschrieben hatten. (den treiber dann aber aufgrund der gleichen gründe die du genannt hast erst mal auf eis gelegt haben?)


----------



## Thomas_v2.1 (30 Oktober 2019)

Jochen Kühner schrieb:


> @thomas_v2.1 gabs hier nicht mal ein link zu einer gruppe die nen java tia treiber entwickeln wollten, und auch ein bisschen übers protokoll geschrieben hatten. (den treiber dann aber aufgrund der gleichen gründe die du genannt hast erst mal auf eis gelegt haben?)



Ja ich stand mit denen mal in Kontakt, und habe da auch meine Bedenken angemeldet. Vielleicht ist es auch gar nicht (mehr) so kritisch zu sehen, Siemens vertreibt mit dem IoT-Gerät ja mittlerweile selber etwas, das mit Node-Red ohne den Nicht-Siemens S7-Treiber im Automatisierungsumfeld annähernd nutzlos ist.


----------



## Jochen Kühner (31 Oktober 2019)

wie war denn die url? finds ncht mehr...


----------



## Hans54216 (31 Oktober 2019)

Bin gerade auf openplclibrary.com gestoßen. Ist diese nur zum öffnen von TIA Projekten oder auch zur Kommunikation?


----------



## Hans54216 (31 Oktober 2019)

S7Comm Plus:
Masterarbeit über S7Comm Plus: https://os-s.de/thesis/MA_Maik_Brueggemann.pdf
Encryption: https://www.blackhat.com/docs/eu-17...Break -The-Security-Wall-Of-S7CommPlus-wp.pdf


----------



## Hans54216 (31 Oktober 2019)

Thomas_v2.1 schrieb:


> In den Code von libnodave würde ich das definitiv niemals einbinden, das ist als Basis nicht mehr zeitgemäß. Ich habe einen ganz rudimentären Treiber für die ganz alte Version der 1200er, dort wird keine Authentifizierung benötigt, damit kann ich den Variablenhaushalt browsen und dann Werte lesen. Im Wireshark Plugin für das neue Protkoll wird weitestgehend alles angezeigt was dort abläuft, um einen Treiber zu schreiben kann man das aber nur als Anhaltspunkt nehmen.
> Das Problem ist m.M.n. eher ein rechtliches als ein technisches, weil dort einige kryptografische Funktionen verwendet werden, von denen du a) wissen musst wie sie funktionieren und b) du ein paar Schlüssel dazu besitzen musst. a) ist seit kurzem von anderer Stelle öffentlich dokumentiert worden, da könnte man sich darauf berufen. Zu b) also Closed-Source Produkte welche das Protokoll unterstützen geben sich Mühe das gut in ihrem Code zu verstecken.


Hallo Thomas,
nach dem du selbst deine eigenen Bedenken ausgeräumt hast, jetzt mal zur Sache.
Auf was würdest du aufsetzen?
Wenn ich das richtig gegoogelt habe, hat Siemens S7CommPlus mehr oder weniger über das bestehende S7Comm drüber gestülpt. Somit macht ein kompletter neu Anfang ja keinen Sinn.

Nach dem Microsoft immer mehr gefallen an Linux hat und damit C# zukünftig (Kauf von Xamarin +Mono) und Umsetzung von DotNet Standard und auch der Chef von Red Hat gefallen an DotNet gefunden hat, darf man C# nicht mehr vernachlässigen.

Ich weiß, dass du ein Freund von C bist, jedoch hast du geschrieben dass du die Zukunft nicht in libnodave siehst. Auf welche Lib würdest du aufsetzen? Snap7? Zukunftsgewand C#, was Leistungmäßig nicht zwangsläufig langsamer ist, jedoch deutlich besser beim Programmieren und der Fehlersuche ist?


----------



## Thomas_v2.1 (1 November 2019)

Hans54216 schrieb:


> Wenn ich das richtig gegoogelt habe, hat Siemens S7CommPlus mehr oder weniger über das bestehende S7Comm drüber gestülpt. Somit macht ein kompletter neu Anfang ja keinen Sinn.



Nein, das hat mit dem alten Protokoll absolut nichts gemeinsam. Die einzige Gemeinsamkeit ist, dass es auch Iso-On-TCP als unterlagertes Protokoll verwendet.


----------



## Jochen Kühner (1 November 2019)

Also wenn ich es machen würde, würd ich das ganze in C# direkt in meiner Bibliothek entwickeln...


----------



## Hans54216 (1 November 2019)

Wie finde ich den die IP Adresse meiner S7 1500 raus, wenn ich nur die MAC hab? S7 ist in einer ET200 verbaut und meldet sich auch per Wireshark, jedoch fehlt mir die IP.


----------



## Thomas_v2.1 (1 November 2019)

Vielleicht hat sie noch keine IP? Wenn du PN-DCP Telegramme mit "Ident Ok" siehst, dann steht dort normalerweise die IP-Adresse.


----------



## Hans54216 (2 November 2019)

Mit TIA hab ich das Gerät und seine IP gefunden.

Hab mir die Demo von AG-Link runter geladen und versuch mich am "AGL5 TIA CommunicationSample C#".
Jedoch bekomme ich keine Verbindung (Fehler Timeout)

AGLINK V4 Konfiguration (Verbindung funktioniert nur jedes zweite mal, und Geräteinfos nur jedes dritte Mal)
Methoden konnte ich mit der GUI gar keine ausführen



```
[FONT=Verdana]AGL_OpenDevice( DevNr=0 ) : Kein Fehler
AGL_DialUp( DevNr=0, boWait=true ) : Kein Fehler
AGL_InitAdapter( DevNr=0, boWait=true ) : Kein Fehler
AGL_GetLifeList( DevNr=0, List, boWait=true ) : 1 
AGL_PLCConnect( DevNr=0, PlcNr=1, boWait=true ) : Timeout
AGL_ExitAdapter( DevNr=0, boWait=true ) : Kein Fehler
AGL_HangUp( DevNr=0, boWait=true ) : Kein Fehler
AGL_CloseDevice( DevNr=0 ) : Kein Fehler
[/FONT]
```


```
[FONT=Verdana]AGL_OpenDevice( DevNr=0 ) : Kein Fehler
AGL_DialUp( DevNr=0, boWait=true ) : Kein Fehler
AGL_InitAdapter( DevNr=0, boWait=true ) : Kein Fehler
AGL_GetLifeList( DevNr=0, List, boWait=true ) : 1 
AGL_PLCConnect( DevNr=0, PlcNr=1, boWait=true ) : Die Verbindung wurde geschlossen
AGL_ExitAdapter( DevNr=0, boWait=true ) : Kein Fehler
AGL_HangUp( DevNr=0, boWait=true ) : Kein Fehler
AGL_CloseDevice( DevNr=0 ) : Kein Fehler
[/FONT]
```


```
[FONT=Verdana]AGL_OpenDevice( DevNr=0 ) : Kein Fehler
AGL_DialUp( DevNr=0, boWait=true ) : Kein Fehler
AGL_InitAdapter( DevNr=0, boWait=true ) : Kein Fehler
AGL_GetLifeList( DevNr=0, List, boWait=true ) : 1 
AGL_PLCConnect( DevNr=0, PlcNr=1, boWait=true ) : Kein Fehler
AGL_ReadMLFBNr( ConnNr=0x400, MLFBNr, boWait=true ) : 6ES7 510-1SJ01-0AB0
AGL_PLCDisconnect( ConnNr=0x400, boWait=true ) : Kein Fehler
AGL_ExitAdapter( DevNr=0, boWait=true ) : Kein Fehler
AGL_HangUp( DevNr=0, boWait=true ) : Kein Fehler
AGL_CloseDevice( DevNr=0 ) : Kein Fehler[/FONT][FONT=Verdana]
[/FONT]
```


----------



## Hans54216 (2 November 2019)

@Thomas:
Braucht man die Erweiterung oder ist das nun alles im aktuellen Wireshark drin? Läuft das unter s7comm oder s7comm-plus?​
https://sourceforge.net/projects/s7commwireshark/



> IMPORTANT
> The s7comm protocol is directly integrated into wireshark (also sources), you don't need the plugin anymore, if you use an actual version of Wireshark.
> 
> To build s7comm-plus for the S7 1200/1500 plc, use the latest sources from Wireshark. Or if you want to use the plugin dll, use the most recent version of Wireshark you can find.​


----------



## Thomas_v2.1 (2 November 2019)

Für s7comm-plus musst du die dll herunterladen und bei deiner Wireshark Installation in das plugins\x.x\epan Verzeichnis legen, dort liegen auch schon andere z.B. für Profinet. Wenn du Wireshark startest dann wird dieses Plugin erkannt und geladen.
Du musst nur die passende Wireshark Version verwenden, aktuell ist die Version 3.0 mit der sollte das Plugin funktionieren.


----------



## Rainer Hönle (2 November 2019)

@Hans54216: Wie ist denn der Timeoutwert eingestellt? Was zeigt wireshark an?


----------



## Hans54216 (2 November 2019)

Rainer Hönle schrieb:


> @Hans54216: Wie ist denn der Timeoutwert eingestellt? Was zeigt wireshark an?



Timout ist auf Default, 30000ms.
Hab gerade nochmal getestet und nun funktioniert die Verbindung. Scheint ein Firewall Problem gewesen zu sein. Hab diese Zwar vorhin schon ausgeschalten hat aber jetzt erst Erfolg gezeigt.


----------



## Hans54216 (2 November 2019)

@[FONT=Verdana,Arial,Tahoma,Calibri,Geneva,sans-serif]Rainer Hönle:
Wie ist den die Performance zwischen S7comm und S7comm Plus bei z.B. S7-1500?
Kostet die Verschlüsselung Zeit oder steigt die Zykluszeit der PLC?
[/FONT]


----------



## Thomas_v2.1 (2 November 2019)

Da wird außer beim Verbindungsaufbau nichts verschlüsselt, jedes Telegramm enthält nur einen HMAC und der ist schnell berechnet.


----------



## Rainer Hönle (2 November 2019)

Hans54216 schrieb:


> Timout ist auf Default, 30000ms.
> Hab gerade nochmal getestet und nun funktioniert die Verbindung. Scheint ein Firewall Problem gewesen zu sein. Hab diese Zwar vorhin schon ausgeschalten hat aber jetzt erst Erfolg gezeigt.



Prima, hätte mich auch gewundert wenn dies nicht ginge bzw. nur mit einer solchen Fehlerrate


----------



## Rainer Hönle (2 November 2019)

Hans54216 schrieb:


> @Rainer Hönle:
> Wie ist den die Performance zwischen S7comm und S7comm Plus bei z.B. S7-1500?
> Kostet die Verschlüsselung Zeit oder steigt die Zykluszeit der PLC?




Da kann ich im Augenblick nur antworten wie Radio Eriwan: das kommt darauf an. Grundsätzlich gilt, dass wenn alles einzelne Symbole sind (also keine Arrays), dann ist das S7comm Plus-Protokoll eher langsamer. Bin im Augenblick dabei, genau diese Frage zu untersuchen und werde die Erkenntnisse dann in einem whitepaper veröffentlichen. Wenn dies soweit ist, werde ich dies hier im Forum sicher kundtun (dauert noch etwas ;-))


----------



## Rainer Hönle (2 November 2019)

Thomas_v2.1 schrieb:


> Da wird außer beim Verbindungsaufbau nichts verschlüsselt, jedes Telegramm enthält nur einen HMAC und der ist schnell berechnet.




Aber die Übertragung nicht als reiner Binärblob sondern als VLQ dauert sicher auch etwas mehr Zeit. Dazu kommt natürlich noch die Zeit, um das Symbol zu finden, da ja keine Speicheradresse angegeben wird. Es ist also insgesamt betrachtet schon ein größerer Aufwand seitens der SPS zu leisten als mit dem normalen S7comm-Protokoll.


----------



## Hans54216 (2 November 2019)

Git es in C# auch ein Beispiel analog zu dem VC "[FONT=Verdana,Arial,Tahoma,Calibri,Geneva,sans-serif]TIA Demo", sprich ohne die Notwendigkeit eines TIA Projektes sondern nur Symbole von der Steuerung laden und anschließend lesen/schreiben?[/FONT]


----------



## Hans54216 (2 November 2019)

Wireshark der Kommunikation hab ich hier mal zusammengestellt.


Anhang anzeigen S7-1510_20191102.zip
​
Wie muss man sich den Symbolischen Zugriff vorstellen?

Symbole werden von der Steuerung geladen und bei der Anfrage wird dann wieder mit DB-Nummer und irgend einer Nummer (oder Hash) gearbeitet?
Muss ich also um Symbolisch eine Variable lesen zu können trotzdem die Adresse zunächst herausfinden? z.B. aus Variablentabelle Online oder TIA Projekt?


----------



## Thomas_v2.1 (2 November 2019)

Jedes Symbol besitzt eine ID. Die Datenbausteine an sich sind wie eh und je mit einer festen Nummer versehen. Für den Zugriff musst du nun die DB Nummer und die IDs für den Zugriff zusammenhängen. Befindet sind ein Symbol innerhalb einer Struktur, dann muss der ganzen Pfad der IDs hintereinandergehängt werden. Die notwendigen IDs kannst du offline aus dem TIA-Portal Projekt auslesen, oder du kannst online den Variablenhaushalt der SPS browsen und daraus die komplette Symbolik mit diesen IDs auslesen. Das Browsen ist relativ aufwändig, weil du dich anhand der IDs im Baum entlang hangeln musst. Es lässt sich aber auch alles in Form von xml-Dateien herunterladen, ich habe mir aber noch nicht im Detail angesehen ob xml effektiver oder einfacher zu verarbeiten ist.

Wenn du "nicht optimierte" DBs verwendest, dann lässt sich über dieses Protokoll auch weiterhin über Absolutadressen lesen oder schreiben. Beim Browsen erhältst du die Absolutadressen ebenfalls.

Optional ist die Symbolprüfsumme. Ist dort ein Wert ungleich Null eingetragen, dann wird aus den Symbolnamen und dem Datentyp eine Prüfsumme gebildet was Fehlzugriffe abfangen soll. Ändert z.B.  jemand in der SPS ein Symbolnamen von "TemperaturOben" zu "TemperaturUnten" so bleibt die ID gleiche, es ergibt sich jedoch eine andere Prüfsumme und ein HMI bekommt ohne Anpassungen keinen Zugriff mehr. Ist die Symbolprüfsumme = 0 dann ist diese Überprüfung nicht aktiv.


----------



## Hans54216 (21 Mai 2020)

Hat von euch schon mal jemand IO-Link Daten über S7comm gelesen/geschrieben?

Hab mir das PCT-Tool vom Step7 angesehen und das kann vom PC Step7 Manager unter Zuhilfenahme der Hardwarekonfig mit IO-Link Master Baugruppen auf der ET200 kommunizieren.
Bei meinem Versuchsaufbau hab ich an der 840d sl (PLC 317) eine ET200 per ProfiBus und auf dieser nen Siemens 4-Port IO-Link Master.

Hab mal die Kommunikation mit geschrieben.

Anhang anzeigen S7-PCT_20200520.rar


----------



## Thomas_v2.1 (21 Mai 2020)

Ich habe mit IO-Link bisher noch nicht gearbeitet, darum sehe ich das auch zum ersten Mal. Ich glaube ich muss meine Unterteilung der Funktion im Protokoll in zwei Nibbles mal überdenken, das war mal schlüssig, aber mittlerweile passt das nur noch mit Ausnahmen.

Verbindungsaufbau geschieht zu TSAP 0xf402, ist das in irgendeiner Weise auf die IO-Link Baugruppe zurückzuführen?

Ansonsten gibt es wohl eine Initialisierungsfunktion, eine Funktion für den Datenaustausch und eine zum Abschließen. Kannst du dir irgendwo anzeigen lassen was für Werte dort ausgelesen werden? Ein einem Telegramm steht zumindest die MLFB einer Siemens Baugruppe. Gibt es zu IO-Link eine Protokollbeschreibung? Vielleicht hat das was man als Datenteil sieht schon etwas mit dem IO-Link Protokoll zu tun.


----------



## Hans54216 (21 Mai 2020)

Ich hab noch mal nen schrieb von der Kommunikation gemacht un ein paar Screenshots der Übertragenen Werte.
Auch hab ich die IODD (Beschreibungsdatei IO-Link) auch mit rein gepackt.

Allgemein zu IO-Link:
vendorId = Eindeutige Herstellernummer (Global eindeutig)
deviceId = Eindeutige Gerätezuordnung (Herstellerspezifisch eindeutig)

Anhang anzeigen S7-PCT_20200521.rar


----------



## Thomas_v2.1 (21 Mai 2020)

Das was da im Datenteil transportiert wird, scheint zumindest sehr speziell zu sein. Vom PCT werden öfters die gleichen Anfragen geschickt, aber in der Antwort kommt immer etwas anderes zurück. Das scheint auf den ersten Blick irgendwie zustandsabhängig zu sein was dort zurückkommt, oder es kann so etwas wie ein Verzeichnis gebrowst werden. Es gibt auch nur ganz selten mal eine Längenangabe vorab, der dann genau diese Anzahl an Bytes folgen.

Ich habe auch schon mal in die Spezifikation geschaut, auf den ersten Blick sehe ich da auch keine Anhaltspunkte. Mit wem spricht die PCT Software denn da, mit dem Master, oder gibt es auch Durchgriff auf die angeschlossenen Geräte?


----------



## Thomas_v2.1 (21 Mai 2020)

Ok, mit deinem letzten Logfile kommt man weiter, und es lässt sich ein Zusammenhang zur IO-Link Spezifikation herstellen.

Z.B. in #257 kommt die Seriennummer zurück. In #248 scheint dieser Datensatz vorselektiert zu werden, mit der 0x15 die sich am Ende findet. 0x15 ist laut Spec der Index für Serial-Number.

Passt auch mit #224 überein. Dort kommt der Produktname zurück, der in #216 mit 0x12 vorgewählt wird.

Es sieht so aus als müsste man vorher etwas anwählen und dann einen Ausführ-Befehl geben. Mal sehen ob der restliche Aufbau sich auch aus der IOL Spezifikation ableiten lässt.


----------



## Hans54216 (21 Mai 2020)

Thomas_v2.1 schrieb:


> Mit wem spricht die PCT Software denn da, mit dem Master, oder gibt es auch Durchgriff auf die angeschlossenen Geräte?


PCT Tool muss mit dem Druckschalter IFM reden, da nur er die ganzen actual Daten hat.

IO-Link verfügt über Zyklische Prozessdaten zur PLC und einen Asynchronen Kommunikationskanal. Dieser Asynchrone Kommunikationskanal kann auch aus der PLC heraus genutzt werden um weitere Daten auszulesen oder z.B. Schaltpunke einzustellen.

Aufbau:
PC -> 840dsl (10.172.26.192) -> Slot? (2->PLC, 4->NC, 5->CP, 6->HMI) -> DP (Adresse 2) -> ET200 (Adresse 3) -> IO-Link Master (Steckplatz 8 ) -> Port1 -> Druckschalter


----------



## Thomas_v2.1 (22 Mai 2020)

Ich komme da auf keinen weiteren Zusammenhang mit der IO-Link Spezifikation. In der ist eine Angabe für den Aufbau zur Anfrage eines ISDU-Containers, das finde ich aber hier nirgends wieder. Wenn du selber mal suchen willst: Im PDF "IOL-Interface-Spec_10002_V112_Jul13.pdf" in Zeile 3946 ist der Aufbau, ab 4252 sind die festen Indizes aufgelistet.

Ich habe mit Wireshark einfach mal in den Daten herumgestochert um eine Struktur zu finden. Nur eine Längenangabe ist zu finden, die aber auch unterschiedliche Bedeutung zu haben scheint.


----------



## Hans54216 (22 Mai 2020)

Thomas_v2.1 schrieb:


> Ich komme da auf keinen weiteren Zusammenhang mit der IO-Link Spezifikation. In der ist eine Angabe für den Aufbau zur Anfrage eines ISDU-Containers, das finde ich aber hier nirgends wieder. Wenn du selber mal suchen willst: Im PDF "IOL-Interface-Spec_10002_V112_Jul13.pdf" in Zeile 3946 ist der Aufbau, ab 4252 sind die festen Indizes aufgelistet.
> 
> Ich habe mit Wireshark einfach mal in den Daten herumgestochert um eine Struktur zu finden. Nur eine Längenangabe ist zu finden, die aber auch unterschiedliche Bedeutung zu haben scheint.


Kann mir auch keinen Reim draus machen.

Hab noch mal ne Aufzeichnung gemacht. Diesmal hab ich in der Hardware Konfig den Parameter des IO-Link Masters auf "Ohne PCT" gestellt. Somit ist kein Download der Beschreibung erforderlich und andererseits kennt das PCT somit die Beschreibung nicht und zeigt nur die Empfangenen Parameter an.

Hab auch ein kleines Video vom PCT Tool mit angehängt.

Anhang anzeigen ohnePCT_S7-PCT_20200522.rar


----------



## Thomas_v2.1 (22 Mai 2020)

Die Angaben Index und Subindex und den Wert in der Antwort findet sich wieder. Das entspricht aber nicht dem Aufbau aus dem IO-Link PDF. Es scheint, das ist eine Mixtur aus IO-Link Standard und einem Eigengewächs drumherum.


----------



## Hans54216 (22 Mai 2020)

Thomas_v2.1 schrieb:


> Die Angaben Index und Subindex und den Wert in der Antwort findet sich wieder. Das entspricht aber nicht dem Aufbau aus dem IO-Link PDF. Es scheint, das ist eine Mixtur aus IO-Link Standard und einem Eigengewächs drumherum.


Das der Siemens sich nicht an Standards hält ist ja unlängst bekannt ;-)


----------



## Thomas_v2.1 (22 Mai 2020)

Auf IO-Link Ebene wird so wie ich das gesehen habe viel mit einzelnen Bits, Nibbles und Bytes und hantiert um das Ganze effektiv zu halten. Das macht vermutlich kein Sinn das alles bis auf Master-Ebene durchzureichen. In den Nutzdaten auf Netzwerkebene stehen an vielen Stellen in einem Byte nur entweder eine 1 oder eine 0. Ich habe auch schon vermutet ob dort vlt. einzelne Bits in einem ganzen Byte untergebracht werden. Da fehlt aktuell der Startpunkt an dem sich ansetzen lässt. Das einzige was man sicher finden kann sind die Indizes/Subindizes und die Daten der Antwort.


----------



## Thomas_v2.1 (22 Mai 2020)

Du könntest vlt. mal eine Aufzeichnung erstellen bei der du nicht nur Gerät 1 anwählst, sondern z.B. mal die 4. Oder nacheinander in definierten Abständen 1, 2, 3, 4. Dann findet man vielleicht diese Zahl wieder.


----------



## Hans54216 (22 Mai 2020)

Thomas_v2.1 schrieb:


> Du könntest vlt. mal eine Aufzeichnung erstellen bei der du nicht nur Gerät 1 anwählst, sondern z.B. mal die 4. Oder nacheinander in definierten Abständen 1, 2, 3, 4. Dann findet man vielleicht diese Zahl wieder.


Mach ich am Montag oder Dienstag. Vorher komm ich nicht mehr an den Teststand. Sensor anstecken geht per VPN schlecht


----------



## Thomas_v2.1 (22 Mai 2020)

Ich habe mir mal eben die Anleitung zu den Siemens IO-Link Funktionsbausteinen angesehen. Mit welchem Wert für ID würdest du diesen aufrufen, also mit der Konfiguration die im Logfile zu sehen ist.
Die 227 (0xe3) für die Siemens Kennung am Parameter CAP findet sich nämlich auch wieder.

Was auch mal interessant wäre, ist wenn du einen Parameter schreibst.


----------



## Hans54216 (23 Mai 2020)

Thomas_v2.1 schrieb:


> Mit welchem Wert für ID würdest du diesen aufrufen, also mit der Konfiguration die im Logfile zu sehen ist.
> Die 227 (0xe3) für die Siemens Kennung am Parameter CAP findet sich nämlich auch wieder.



CAP:
Siemens spezifisch: 227
Andere Hersteller (Master): 0xB400 (-19456)

ID: Adresse in der HW-Konfig




Beispiel für den Sensorname Index 18







Thomas_v2.1 schrieb:


> Was auch mal interessant wäre, ist wenn du einen Parameter schreibst.


Hab noch nicht rausgefunden ob das mit dem PCT Tool überhaupt geht. Soweit ich sehe kann man nur die IODD zum Master schreiben/lesen und online nur die Parameter betrachten.


----------



## Thomas_v2.1 (24 Mai 2020)

Soweit ich das sehe wird die CAP häufig nur zur Anfrage/Antwort-Kennung verwendet.
Die ID der Anfangsadresse der Baugruppe finde zumindest ich so wie ich das aktuell sehe nicht wieder. Da stellt sich die Frage, was macht das PCT wenn du mehrere IO-Link Baugruppen an einer CPU hast, wie werden diese angesprochen? Da hilft nur ausprobieren, Adressen ändern, laden, abfragen und prüfen ob und wo sich etwas ändert.

So wie es aussieht ist die Interpretation einiger Daten von vorigen Daten abhängig (kontextsensitiv), was es nicht leichter macht das Protokoll nachzuvollziehen.
Auch wenn ich IO-Link selber bisher nicht verwendet habe, könnte ich es mir schon nützlich vorstellen, diverse Diagnosedaten von extern abfragen zu können ohne das SPS-Programm anfassen zu müssen. Darum ist es vielleicht sinnvoll, alles zu diesen Thema in einen separaten Thread zu verschieben, da es mit NC ja nicht mehr direkt etwas zu tun hat. Wobei das mit der S7-300 ja auch alles "Legacy" Hardware ist.


----------



## tld70 (23 November 2020)

Hallo zusammen,
ich bin neu hier und bei der Suche im Internet auf dieses Forum gestossen, und  hoffe auf Hilfe.
kann mir jemand vielleicht helfen?
Mittlerweile habe ich eine Verbindung über einen PI S7 USB und PLCVcom bei einer 840D PL über X122 hinbekommen
und ich kann mit:

        conn = new PLCConnection(config);

        conn.Connect();

     List<PLCTag> tags1 = new List<PLCTag>
                {
                    new PLCTag("AB0"),            // LED Signale zur MSST      // hier die Variabeln eintragen für Zustandswerte
                    new PLCTag("AB1"),            // LED Signale zur MSST      // hier die Variabeln eintragen für Zustandswerte
                    new PLCTag("DB21.DBB4"),      // VS Poti Bit 0-4
                    new PLCTag("DB34.DBB19"),     // HS Poti Bit 0-4
                    new PLCTag("DB10.DBB56"),     // Estop....
                    new PLCTag("DB21.DBB7")
                };


    conn.ReadValues(tags1);

        int count = 0;

            foreach (var plcTag in tags1)
            {

                SiemensMode(plcTag.Value != null ? Convert.ToString(Convert.ToInt32(plcTag.Value), 2).PadLeft(8, '0') : "", count);

                count++;
            }


Auch die PLC Statusvariabeln auslesen.

Aber wie schaffe ich es auf die NC zuzugreifen?
z.B. auf das Directory der NC Programme, Zyklen oder GUDs?
Evtl auch Parameter?
Wie kann ich diese runterladen und auch wieder hochladen?

Gibt es ein Beispiel?

Würde mich über eine Hilfe freuen.

Thomas


----------



## Hans54216 (23 November 2020)

Ich hab keine PL. Die Erweiterung der Lib hab ich mit einer 840d SL gemacht. Diese hat Netzwerk Ports für die Kommunikation. Über den MPI hat es bei einem kleinen Test nicht funktioniert (nur zur PLC), wobei ich nicht weiß ob die Verbindung zur NC bei der SL überhaupt funktioniert. 

Kannst du einen Screenshot der Hardware Konfiguration 840 d schicken?

Was übergibst du für config bei
'new PLCConnection(config)'


----------



## tld70 (24 November 2020)

Hallo Hans,
also ein Beispiel für die SL wäre auch gut.
Bald komme ich an eine SL ran zum testen.
Nur momentan habe ich keine SL.
HW Config schick ich mit,.


 var config = new PLCConnectionConfiguration();

                config.ConfigurationType = LibNodaveConnectionConfigurationType.ObjectSavedConfiguration;
                config.ConnectionType = LibNodaveConnectionTypes.MPI_über_Serial_Adapter;
                config.BusSpeed = LibNodaveConnectionBusSpeed.Speed_187k;
                config.LokalMpi = 0;
                config.ComPort = 8;
                config.ComPortSpeed = "38400";
                config.ComPortParity = LibNodaveConnectionBusParity.even;
                config.CpuIP = "192.168.101.0" ;
                config.CpuSlot = 2;
                config.CpuMpi = 2;
                config.EntryPoint = "S7ONLINE";


                conn = new PLCConnection(config);;

Der Adapter ist ein S7 USB von PI und ist über USB verbunden.
Also über MPI sollte es doch auch funktionieren, oder?
Sinucom NC und die HMI SW geht ja auch über X122 ( MPI Adresse 3 ).

Thomas


----------



## Hans54216 (25 November 2020)

Ist das die Hardware Konfig mit der die PL funktioniert? Bei der SL taucht diese auch in der Hardware Konfig auf.




Beispiel für ISO-Over-TCP/IP
using (var myConn = new DotNetSiemensPLCToolBoxLibrary.Communication.PLCConnection("test"))
{
myConn.Configuration.CpuIP = !string.IsNullOrEmpty(IPAddress) ? IPAddress : "192.168.214.1";
myConn.Configuration.CpuSlot = plcConnection ? 2 : 4;
myConn.Connect();
var r1 = myConn.ReadValue(new NC_Var(0x82, 0x41, 0x1, 0x1, 0x15, 0x1, 0xF, 0x8));
}


----------



## Hans54216 (25 November 2020)

Hallo Thomas,

kannst du irgendwie eine Aufzeichnung der Kommunikation machen? Wireshark (USB) oder ähnliches.


----------



## tld70 (25 November 2020)

Hallo Hans,
also das ist die PL die ist aber in keiner Maschine, sondern hängt an der Wand als Teststand.

Leider habe ich noch nie eine Aufzeichnung gemacht.
In deinem Beispiel steht eine IP adresse, die NCU hat aber kein Netzwerk also auch kein IP.

var r1 = conn.ReadValue(new NC_Var(0x82, 0x41, 0x1, 0x1, 0x15, 0x1, 0xF, 0x20));
was soll hier zurückgegeben werden? r1 bleibt NULL
MPI habe ich 2 und 3 probiert, der Wert bleibt auf NULL bei 2 und ist 20 bei 3.


----------



## Hans54216 (25 November 2020)

Hab ja oben geschrieben, dass das Beispiel für ISO-Over TCP/IP ist (Solution Line)


----------



## tld70 (25 November 2020)

OK vielen Dank,
gibts noch eine kurze Beschreibung über die Werte, was die 0x werte bedeuten?


----------



## Hans54216 (25 November 2020)

Um auf eine NC-Variable zuzugreifen benötigst du die zugehörige Adresse. Diese bekommst du anhand des NC-VAR-SELECTOR (Siemens).

Hab ich hier im Verlauf schon alles geschrieben. Einfach mal die vorigen Seiten durchsuchen oder bei google eingeben.


----------



## Hans54216 (25 November 2020)

Hab gerade nach einem PL Projekt geschaut.

CpuSlot ist hier wohl auch 2 für die PLC und 4 für die NC.
Außerdem wird für die NC auch eine eigene MPI-Adresse aufgeführt.


----------



## tld70 (25 November 2020)

Alles klar, vielen Dank.
Damit müsste ich erstmal klarkommen.

Nur dachte es gibt möglichkeiten wie bei FANUC Focas um auf alle NC Daten ( Programme, Directory... ) zuzugreifen,
das ist hier nicht möglich, oder?
Wie bei Fanuc z.B sowas: ret = Focas1.cnc_rdprogdir2 (FlibHndl,0,ref top, ref num, prg);
odersowas:
short ret = Focas1.cnc_upstart3(FlibHndl,0,sprg,eprg);


----------



## Hans54216 (26 November 2020)

Datei Up/Download, PI-Dienste, Variablen lesen/schreiben,...
Ist implementiert, jedoch anhand einer SL mit Ethernet Port.

In wieweit das auch für PL funktioniert weiß ich nicht. Ich hab auch keine PL zum Testen.


----------



## tld70 (8 Dezember 2020)

Danke Hans, sobald ich mein anderes Problem gelöst habe, werde ich dort weitermachen.

Jetzt habe ich aber ein anderes Problem:
Ich habe erfolgreich eine Verbindung mit einer PowerLine am X122
mit einem PI S7-USB und PLCVCOM
Jetzt möchte ich die S7 DLL verwenden, die ging früher mal.
Also mit Step7 tut diese Verbindung einwandfrei,
Mit dieser DLL kommt eine Fehlermeldung, Siehe Bild.

Was mache ich falsch? oder wer kann mir helfen?
Mit einer älteren Version von 2011 ging es noch
Siehe Bild.
Ich habe W10 64bit Version 20H2


----------



## DeltaMikeAir (8 Dezember 2020)

tld70 schrieb:


> Ich habe W10 64bit Version 20H2



Ich kann dir bei deinem Problem nicht helfen, wollte dir nur sagen dass die Win10 20H2 Variante noch mit Vorsicht zu genießen ist:

Siemens Warnung zum Windows 10 Update 20H2 ( Oktober )


----------



## Windoze (9 Dezember 2020)

Der Fehler kann auftreten, wenn du eine 32bit DLL in einem 64bit Programm laden willst. Oder auch umgekehrt.


----------



## tld70 (9 Dezember 2020)

Hallo,
also wenn ich das Beispiel WPFToolboxForPLCs in der Toolbox DotNetSiemensPLCToolBoxLibrary-master direkt starte, kommt dieser Fehler. Eine alte Version von 2011, die ich irgendwo im Netz gefunden habe, bei der funktioniert es. Direkt auf diesem Computer mit der gleichen Hardware...


----------



## tld70 (24 Dezember 2020)

Hallo,
also ich habe es geschafft, das die Toolbox mit der S7DLL kommuniziert.
Ich musste die Libary als 32 Bit compilieren.
Jetzt kommt aber ein Fehler mit einer IP Adresse, obwohl es in der Verbindung keine IP geben sollte.
hier ein Bild.
Mache ich etwas falsch?
Die alte Version tut aber.


----------



## tld70 (15 März 2021)

Hallo,
vielleicht kann mich jemand unterstüzen,
hat es jemand schonmal mit der neuen Version von DotNetSiemensToolbox geschafft über die S7DLL an einer 840D PL online zu kommen,
wenn ja wie?
Bei mir kommt beim versuch eine Verbindung aufzubauen folgender Fehler:






Verbindung über COM funktionieren.

Gibt es außerdem eine Möglichkeit ein NCK oder PLC archiv zu erstellen?
So ähnlich wie Sinucom?

Danke für die Unterstützung

Thomas


----------

