RE: Software schreiben zum steuern von Loks?

#51 von st-oldie , 17.11.2014 18:33

Hallo ALWIM,

Zitat von ALWIM
Muss ich sowie so, da ich von Assembler keine Ahnung habe!



Und wie sieht es jetzt mit Bitoperationen (shift, and, or) aus. Soll das jetzt kurz erklären? Oder soll ich mit dem Märklin CS2 Protokoll anfangen? Diese Operationen brauchst du ja für das Erstellen der Nachricht und um die Werte in den String zu packen.

Tschüß
Michael


st-oldie  
st-oldie
InterRegioExpress (IRE)
Beiträge: 458
Registriert am: 22.12.2009
Homepage: Link
Ort: Friedberg (Hessen)
Gleise Märklin K-Gleis
Spurweite H0
Steuerung Märklin Systems
Stromart Digital


RE: Software schreiben zum steuern von Loks?

#52 von ALWIM , 18.11.2014 16:02

Zitat
Oder soll ich mit dem Märklin CS2 Protokoll anfangen?


Kannst ja mal mit dem CS2 Protokoll anfangen. Ich komme im Moment eh nicht dazu an dem Projekt was zu machen, da ich fast keine Zeit habe.

Edit:
Mit meinem selbstgeschriebenen Testprogramm, konnte ich die CS2 in den Stoppmodus setzen!!!
Der Stoppbefehl funktioniert also schon mal!!!
Jetzt kann ich Plan A in die Tat umsetzen!!!
Ich danke allen die mir geholfen haben!!!



Einfach herrliich! Da kommt Freude auf!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
 

#INCLUDE ONCE "TSNE_V3.bi" 'Die TCP Netzwerkbibliotek integrieren
 
SCREENRES 640, 320, 32
 
DIM G_ClientRX AS UINTEGER 'Eine Variable für den Client-Handel erstellen
DIM G_ClientTX AS UINTEGER 'Eine Variable für den Client-Handel erstellen
 
DIM SHARED i AS INTEGER ' als Laufvariable
DIM SHARED myDLC AS BYTE ' Anzahl der Datenbytes im CAN-Paket, 1 Byte (eigentlich nur ein Nibble)
DIM SHARED myPrio AS BYTE ' Priorität des befehls, 1 Nibble (4 Bits)
DIM SHARED myResponseBit AS BYTE ' wenn wir als PC-Programm senden, ist dieses Bit immer 0
DIM SHARED myStartWord AS USHORT ' die Kombination aus Prio, Command und Responsebit
DIM SHARED myUID AS ULONG ' Zieladresse des Objektes auf dem CAN, 32 Bits
DIM SHARED myHash AS USHORT ' unser Hash, 16 Bits
DIM SHARED myCommand AS BYTE ' unser Befehl, 8 Bits
DIM SHARED mySubCommand AS BYTE ' unser Unterbefehl, 8 Bits
DIM SHARED myDataBytes(0 TO 7) AS BYTE ' array[0..7] of Byte, immer genau 8 Bytes
 
DIM SHARED mySendingString AS STRING ' diese Zeichenkette werden wir über das UDP-Socket senden
DIM SHARED Befehl AS STRING
 
myPrio = 0 ' wir haben keine Priorität
myCommand = &h00 ' Systembefehl
mySubCommand = 0 ' Stopp
myHash = &h4711 ' wie im Beispiel, kann aber auch &h0300 sein (als Minimum)
myDLC = &h05 ' 5 Bytes Nutzdatenlänge
myUID = &h00000000 ' UID = 0 bedeutet: sende den Befehl an alle
 
' Inits
FOR i = 0 TO 7 ' Märklins Doku zählt auch von D0 .. D7
myDataBytes(i) = 0 ' init array
NEXT
 
DECLARE SUB TSNE_NEWDATAUDP (BYVAL V_TSNEID AS UINTEGER, BYVAL V_IPA AS STRING, BYREF V_Data AS STRING)
DECLARE SUB SENDESTOPCS2
 
DIM BV AS INTEGER 'Variable für Statusrückgabe erstellen
 
BV = TSNE_Create_UDP_TX(G_ClientTX) 'UDP-Socket zum senden erstellen
' Statusrückgabe auswerten
IF BV <> TSNE_Const_NoError THEN
PRINT "[FEHLER] " & TSNE_GetGURUCode(BV) 'Fehler ausgeben
END -1 'Programmbeenden
END IF
 
BV = TSNE_Create_UDP_RX(G_ClientRX, 1234, @TSNE_NEWDATAUDP) 'UDP-Socket für den Empfang erstellen
' Statusrückgabe auswerten
IF BV <> TSNE_Const_NoError THEN
PRINT "[FEHLER] " & TSNE_GetGURUCode(BV) 'Fehler ausgeben
END -1 'Programmbeenden
END IF
 
PRINT "[OK]" 'Verbindung wurde erfolgreich hergestellt.
 
SENDESTOPCS2
 
LOCATE 5,5: PRINT "mySendingString: "; mySendingString
 
DO
 
IF MULTIKEY(&h26) THEN BV = TSNE_Data_Send(G_ClientTX, mySendingString, , "169.254.203.235", 15731) 'Senden an DIREKT an sich selbst
 
IF BV <> TSNE_Const_NoError THEN
PRINT "[FEHLER] " & TSNE_GetGURUCode(BV) 'Fehler ausgeben
SLEEP
END -1 'Programmbeenden
END IF
 
IF MULTIKEY(&h01) THEN
TSNE_Disconnect(G_ClientTX) 'UDP-Socket wieder schliessen
TSNE_Disconnect(G_ClientRX) 'UDP-Socket wieder schliessen
PRINT "[WAIT] ..." 'Warte auf das ende der Verbindung (Disconnect)
TSNE_WaitClose(G_ClientTX)
TSNE_WaitClose(G_ClientRX)
PRINT "[WAIT] OK"
PRINT "[END]"
SLEEP
END 'Anschliessend beenden wir unser Programm
END IF
 
SLEEP 1000
LOOP
 
SLEEP
END
 
SUB SENDESTOPCS2
 
' Kombination
myStartWord = ( ((myPrio SHL 12) + (myCommand SHL 1) + (myResponseBit AND 1)) AND &hFFFF )
myDataBytes(0) = ((myUID SHR 24) AND &hFF) ' Big Endian encoding
myDataBytes(1) = ((myUID SHR 16) AND &hFF)
myDataBytes(2) = ((myUID SHR 8) AND &hFF)
myDataBytes(3) = (myUID AND &hFF)
myDataBytes(4) = mySubCommand
 
' wir stellen nun die Daten als String dar
mySendingString = CHR((myStartWord SHR 8) AND &hFF) + CHR(myStartWord AND &hFF)
mySendingString = mySendingString + CHR((myHash SHR 8) AND &hFF) + CHR(myHash AND &hFF)
mySendingString = mySendingString + CHR(myDLC AND &hFF)
FOR i = 0 TO 7
mySendingString = mySendingString + CHR(myDataBytes(i) AND &hFF) ' wir gehen mit "AND &hFF" auf Nummer sicher...
NEXT
 
mySendingString = LEFT(mySendingString, 13)
 
END SUB
 
Sub TSNE_NewDataUDP (ByVal V_TSNEID as UInteger, ByVal V_IPA as String, ByRef V_Data as String) 'Empfänger für neue Daten (UDP)
'Beim UDP-Modus wird nicht nur die empfangenen Daten, sondern auch die IP des senders übergeben.
Print "[NDA]: >" & V_IPA & "<___>" & V_Data & "<"
End Sub
 



Gruß
ALWIM


Mein letzter Zugang:
1x Lockdown...


ALWIM  
ALWIM
InterRegio (IR)
Beiträge: 219
Registriert am: 05.04.2014


RE: Software schreiben zum steuern von Loks?

#53 von PaSchu ( gelöscht ) , 19.11.2014 19:13

Freut mich das es am Ende geklappt hat.

Noch mehr freut mich das Du dich von den Negativschreibern am Anfang des Threads nicht von deinem Vorhaben hast abbringen lassen. Jemand der andere Wege geht hat es nicht immer einfach.


PaSchu

RE: Software schreiben zum steuern von Loks?

#54 von ALWIM , 19.11.2014 19:59

Zitat
Freut mich das es am Ende geklappt hat.


Freu dich nicht zu früh! Noch bin ich nicht da, wo ich hin will!
Bis jetzt klappt nur, ein- und ausschalten des Stromes!

Zitat
Noch mehr freut mich das Du dich von den Negativschreibern am Anfang des Threads nicht von deinem Vorhaben hast abbringen lassen.


Das freut mich auch! Ich wusste ja, dass es mit Basic (Freebasic) klappt! Das wusste ich schon, bevor ich überhaupt eine Zeile programmiert habe.

Zitat
Jemand der andere Wege geht hat es nicht immer einfach.


Stimmt! Diese Erfahrung habe ich schon mal im Beruf gemacht. Wenn man weiß wie es geht, bringt man es auch mit Basic relativ schnell hin!

Bei der Lokomotive (steuern, Funktionen auswählen) mache ich mir noch sorgen. Da weiß ich noch nicht genau wie die Definition aussehen muss!

So muss ja der Stoppbefehl aussehen:

1
2
3
4
5
6
 
myPrio = 0          ' wir haben keine Priorität
myCommand = &h00 ' Systembefehl
mySubCommand = 0 ' Stopp
myHash = &h4711 ' wie im Beispiel, kann aber auch &h0300 sein (als Minimum)
myDLC = &h05 ' 5 Bytes Nutzdatenlänge
myUID = &h00000000 ' UID = 0 bedeutet: sende den Befehl an alle
 



Den Fahrbefehl schluckt er irgendwie noch nicht so ganz! Aber das kriege ich auch noch hin.
Strom aus- und einschalten klappt einwandfrei!

Gruß
ALWIM


Mein letzter Zugang:
1x Lockdown...


ALWIM  
ALWIM
InterRegio (IR)
Beiträge: 219
Registriert am: 05.04.2014


RE: Software schreiben zum steuern von Loks?

#55 von st-oldie , 20.11.2014 18:14

Hallo ALWIM,

Zitat von ALWIM
Mit meinem selbstgeschriebenen Testprogramm, konnte ich die CS2 in den Stoppmodus setzen!!!
Der Stoppbefehl funktioniert also schon mal!!!
Jetzt kann ich Plan A in die Tat umsetzen!!!
Ich danke allen die mir geholfen haben!!!



Glückwunsch! Da hast du ja mehr Zeit dafür gehabt als ich. Dann hast du ja die Umsetzung der Zahlen in den String fürs Versenden im Griff. Um eine Lok zu steuern, mußt du nur das richtige Kommando, Subkommando, DLC (= Anzahl benutzter Datenbytes) und die richtigen Datenbytes senden. Da ist nur das Problem, die UID der Lok zu ermitteln.

Ich fürchte, ich hab auch die nächsten Tage etwas wenig Zeit, etwas ausführlicher zu antworten.

Tschüß
Michael


st-oldie  
st-oldie
InterRegioExpress (IRE)
Beiträge: 458
Registriert am: 22.12.2009
Homepage: Link
Ort: Friedberg (Hessen)
Gleise Märklin K-Gleis
Spurweite H0
Steuerung Märklin Systems
Stromart Digital


RE: Software schreiben zum steuern von Loks?

#56 von ALWIM , 21.11.2014 17:20

Zitat
Glückwunsch! Da hast du ja mehr Zeit dafür gehabt als ich.


Mehr Zeit nicht, aber man hat mir einen Quellcode in C gepostet! Den habe ich dann auf die Programmiersprache Freebasic umgeschrieben und entsprechend auf meine Bedürfnisse angepasst. Strom ein- und ausschalten klappt!

Zitat
Um eine Lok zu steuern, mußt du nur das richtige Kommando, Subkommando, DLC (= Anzahl benutzter Datenbytes) und die richtigen Datenbytes senden.


Das ist klar! Wobei mir noch nicht ganz klar ist, wo da die Geschwindigkeit definiert wird!

Zitat
Da ist nur das Problem, die UID der Lok zu ermitteln.


Das ist ein Problem. Ein großes sogar! Kann man die UID irgendwie errechnen bzw. anzeigen lassen? Das würde das ganze erheblich erleichtern!

Ich frage mich nur, wann Märklin endlich für die CS 2, die Version 3.8 rausbringt? Wird ja langsam Zeit oder nicht? Und der 5. Dezember ist auch so ein Tag auf den ich warte (wegen dem TGV)!

Gruß
ALWIM


Mein letzter Zugang:
1x Lockdown...


ALWIM  
ALWIM
InterRegio (IR)
Beiträge: 219
Registriert am: 05.04.2014


RE: Software schreiben zum steuern von Loks?

#57 von st-oldie , 22.11.2014 00:02

Hallo ALWIM,

Zitat von ALWIM
Mehr Zeit nicht, aber man hat mir einen Quellcode in C gepostet! Den habe ich dann auf die Programmiersprache Freebasic umgeschrieben und entsprechend auf meine Bedürfnisse angepasst. Strom ein- und ausschalten klappt!



Ah, deshalb ging das so schnell. Es ist noch eine Vereinfachung mit dem Hash in deinem Code.

Zitat von ALWIM

Zitat
Um eine Lok zu steuern, mußt du nur das richtige Kommando, Subkommando, DLC (= Anzahl benutzter Datenbytes) und die richtigen Datenbytes senden.


Das ist klar! Wobei mir noch nicht ganz klar ist, wo da die Geschwindigkeit definiert wird!




Das ist recht einfach und steht in der Beschreibung der entsprechenden Nachricht. Du mußt dir dazu in der Märklin Doku die Beschreibung des entsprechenden Befehls durchlesen. Der Teil beschreibt, was in den Datenbytes steht. Und da ist für den Fahrbefehl auch die Geschwindigkeit.

Zitat von ALWIM

Zitat
Da ist nur das Problem, die UID der Lok zu ermitteln.


Das ist ein Problem. Ein großes sogar! Kann man die UID irgendwie errechnen bzw. anzeigen lassen? Das würde das ganze erheblich erleichtern!




Es gibt eine Möglichkeit, sich diese 'Information zu besorgen.

Gib mir bitte noch etwas Zeit.

Ich hatte die Woche versucht, nach dem Update meines Beaglebone Black auf Ubuntu 14.04 Trusty auch den CAN Controller wieder zum Laufen zu bringen. Leider fehlt mir noch Grundlagenwissen über den device tree. Mit diesem kleinen ARM basierenden Minicomputer hab ich die CAN Nachrichten der MS2 gelesen, dekodiert und auch über Ethernet verschickt. Und die Nachrichten der Märklin APP an die Gleisbox (und MS2) weitergeleitet. Ich hab dabei die Nachrichten in ein Zwischenformat konvertiert. Da alles funktioniert, hab ich die Nachrichtne richtig dekodiet und kodiert. Und es gab noch einige Dinge zu beachten, die Märklin nicht erklärt hat. Zusätzlich mußte ich die Datei lokomotive.cs2 mit allen in meiner MS2 gespeicherten Loks ais den Infos der MS2 selbst erzeugen.

Jetzt am Wochenende sind auch noch Veranstaltungen.

Ich würde dann demnächst der Reihe nach einfach nochmals die folgenden Dinge hier erklären:

1. Aufbau der CAN Nachricht aus Meldungskennung, DLC und Datenbytes und wie das auf ein Bytearray aufzuteilen ist. Das ist der Teil, den du in deinem Code schon gemacht hast. Aber vielleicht möchte das noch jemand "in Prosa" anstelle von Code lesen.
2. Erklärung, aus welchen Teilen sich die Meldungskennung zusammensetzt. Auch das hast schon zum Teil gemacht. Aber da fehlt noch die Berechnung des Hash aus der eigenen UID. Da hast du bisher eine Konstante benutzt (was auch ok ist).
3. Einige Befehle als Beispiel. Da wird dann auch der Befehl kommen, mit dem du die Lok steuern kannst.
4. Erklärung der Datei lokomotive.cs2, die du z.B. über einen Webbrowser aus der CS2 auslesen. Damit kommst du auch an die UID der Lok. Das hab ich noch nicht versucht, da ich bisher nur die Nachrichten durchgereicht habe, aber nicht selbst etwas gesteuert. habe. Und ich habe keine CS2.

Tschüß
Michael


st-oldie  
st-oldie
InterRegioExpress (IRE)
Beiträge: 458
Registriert am: 22.12.2009
Homepage: Link
Ort: Friedberg (Hessen)
Gleise Märklin K-Gleis
Spurweite H0
Steuerung Märklin Systems
Stromart Digital


RE: Software schreiben zum steuern von Loks?

#58 von ALWIM , 22.11.2014 01:30

1
 
Gib mir bitte noch etwas Zeit.
 


Gib ich dir! Im Moment habe ich (eigentlich) selber wenig Zeit! Gewisse Dinge gehen vor. Deshalb kann ich da sowieso nicht an meinem Projekt weitermachen.

Zitat
Jetzt am Wochenende sind auch noch Veranstaltungen.


Bei mir auch!

Zitat
Das ist recht einfach und steht in der Beschreibung der entsprechenden Nachricht. Du mußt dir dazu in der Märklin Doku die Beschreibung des entsprechenden Befehls durchlesen. Der Teil beschreibt, was in den Datenbytes steht. Und da ist für den Fahrbefehl auch die Geschwindigkeit.


Wenn es so einfach wäre, hätte ich schon längst ein komplett fertiges Programm in den Händen!
Eilt aber nicht! Ich habe genügend Zeit!!!
Aber es erstaunt mich, dass man mit so einfachen Mitteln die CS 2 ansteuern kann!



Gruß
ALWIM


Mein letzter Zugang:
1x Lockdown...


ALWIM  
ALWIM
InterRegio (IR)
Beiträge: 219
Registriert am: 05.04.2014


RE: Software schreiben zum steuern von Loks?

#59 von HansK2 , 22.11.2014 21:42

Hallo zusammen,
um den Thread nicht aus den Augen zu verlieren mache ich mal hier einen Kommentar.
Ich finde das Thema sehr interessant und die Diskussion am Anfang fand ich sehr amüsant.
Selberster verdiene ich seit Ewigkeiten mein Geld mit Software-Entwicklung (wenn ich runde, sind es 40 Jahre), mit vielen Programmiersprachen habe ich im Laufe der Zeit gearbeitet. Irgendwann habe ich aufgehört zu zählen. BASIC war ganz am Anfang auch mit dabei ..., aber auch Assembler und C.

Kennt Ihr eigentlich das CAN-Digital-Bahn-Projekt, siehe http://www.can-digital-bahn.com ?
Vielleicht könntet Ihr von dort noch ein paar Tipps und Infos bekommen?

Gruß aus dem Westerwald
Hans


HansK2  
HansK2
RegionalExpress (RE)
Beiträge: 74
Registriert am: 06.05.2012


RE: Software schreiben zum steuern von Loks?

#60 von st-oldie , 23.11.2014 23:38

Hallo Hans,

Zitat von HansK2
Ich finde das Thema sehr interessant und die Diskussion am Anfang fand ich sehr amüsant.
Selberster verdiene ich seit Ewigkeiten mein Geld mit Software-Entwicklung (wenn ich runde, sind es 40 Jahre), mit vielen Programmiersprachen habe ich im Laufe der Zeit gearbeitet. Irgendwann habe ich aufgehört zu zählen. BASIC war ganz am Anfang auch mit dabei ..., aber auch Assembler und C.



Ja, ging mir ähnlich. Bei mir sind es noch keine 40 Jahre. Und da ich aktuell mit Linux auf embedded systems programmiere, bin ich im Moment auch bei C. Ich hatte auch mal Basic vor Jahren kennen gelernt. Und dieses Basic war in der Tat damals nicht ernstzunehmen.

Ich hatte mich eingemischt und meine Hilfe angeboten, weil ich auch fand, daß die Diskussion am Anfang völlig daneben und nicht zielführend war. Und weil ich das Märklin Protokoll schon recht gut verstanden habe. Und es scheint ja auch Mitleser zu geben, die wirklich etwas darüber lernen wollen.

Außerdem wollte ich den Thread wieder auf das eigentliche Thema zurückführen und helfen, das Märklin Protokoll zu verstehen.

Zitat von HansK2
Kennt Ihr eigentlich das CAN-Digital-Bahn-Projekt, siehe http://www.can-digital-bahn.com ?
Vielleicht könntet Ihr von dort noch ein paar Tipps und Infos bekommen?



Das Projekt kenne ich. Ich hab den Startpunkt 2 und daran einen SBC mit Arm (beaglebone black) angeschlossen. Das BBB nimmt die CAN Nachrichten, dekodiert sie und leitet sie in mein System weiter. Dann gibt es einen Teil, der sie wieder codiert und dann per UDP weiterleitet. Damit kann ich mit der Märklin APP fürs Smartphone alle Loks steuern, die meine MS2 gespeichert hat. Allerdings gibt es im can-digital-bahn projekt nicht ganz so viel Informationen über das Märklin CAN Protokoll. Die setzen meist fertige Komponenten ein. Aber ich denke, daß ich das Märklin CAN Protokoll gut genug verstehe..

Tschüß
Michael


st-oldie  
st-oldie
InterRegioExpress (IRE)
Beiträge: 458
Registriert am: 22.12.2009
Homepage: Link
Ort: Friedberg (Hessen)
Gleise Märklin K-Gleis
Spurweite H0
Steuerung Märklin Systems
Stromart Digital


RE: Software schreiben zum steuern von Loks?

#61 von st-oldie , 23.11.2014 23:46

Teil 1: Aufbau der CAN Nachricht und Abbildung auf eine UDP Sendepuffer

Die Märklin CAN Nachricht besteht aus den folgenden Komponenten:

  • Meldungskennung
    Dies sind 29 Bits. Da sich die Meldungskennung aus verschiedenen Teilen zusammensetzt, sollte hierfür ein nicht vorzeichenbehafteter Wert gewählt werden . Wir können also eine 32 Bit Ganzzahl nehmen (unsigned long für die meisten C Compiler)
  • DLC
    Dieses Feld beschreibt, wieviel Datenbytes folgen. Es werden nur 4 Bit benutzt, also könen wir ein Byte dafür nehmen.
  • Bis zu 8 Datenbytes.
    Hierfür können wir ein Feld von 8 Bytes verwenden.


Dies ergibt sich aus dem Datenformt der CAN sockets, die immer die folgenden Struktur übertragen:

1
2
3
4
5
 
struct can_frame {
canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
__u8 can_dlc; /* data length code: 0 .. 8 */
__u8 data[8] __attribute__((aligned(8)));
};
 



Diese Struktur enthält eine 32 Bit can_id, die bei Märklin als Meldungskennung benutzt wird. Danach kommt die can_dlc, die die Anzahl benutzter Bytes in den Daten abgibt. Und dann kommen 8 Byte Daten, von denen in den Märklin Nachrichten nicht immer alle Bytes benutzt werden.

Über UDP werden aber nur Bytes verschickt. Wie werden nun diese Werte von Märklin in eine Folge von Bytes überführt?

Zuerst müssen die 29 Bits der Meldungskennung verteilt werden. Dazu werden einfach die 4 Bytes unseres unsigned long auf die ersten 4 Bytes verteilt.

Unser unsigned long besteht aus 4 Bytes. Üblicherweise schreibt man in einer Hex- bzw. Binärdarstellung das höchstwertige Bit (MSB = most signifcant bit) ganz links und das niederwertigste (LSB = less significant bit) ganz rechts:

1
2
 
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7  6 5 4  3 2 13
Byte 1 | Byte 2 | Byte 3 | Byte 4
 



Es gibt nun 2 Möglichkeiten für die Reihefolge der Bytes. Wir können in das erste Byte unserer CAN Nachricht das Byte mit dem niederwertigsten Bit schreiben, dann das nächste, ... und zum Schluß das höchstwertige Byte. Diese Reihenfolge nennt man "little endian" (die Intel Reihenfolge, weil die Intel 80x86 CPUs diese Reihenfolge benutzen). Oder man schreibt in das erste Byte der CAN Nachricht das Byte mit dem höchstwertigen Bit, ... und in das vierte Byte das Byte mit dem niederwertigsten Bit. Diese Reihenfolge nennt man "big endian" (die Motorola Reihenfolge, weil die Motorola 68000 CPUs diese Reihenfolge benutzen). Die Bezeichnung little und big endian geht auf Gullivers Reisen zurück, wo es die Frage gab, ob ein Ei am stumpfen Ende (big end) oder am spitzen Ende (little end) aufgeschlagen werden muß.

Bei CAN wird wie bei Ethernet big endian benutzt.

Also fangen wir beim obersten Byte an und kopieren dieses in das erste Byte von unserem Sendepuffer. Man bekommt das oberste Byte, indem man alle Bits um 24 Stellen nach rechts verschiebt. Danach sind alle 8 oberen Bits im untersten Byte gelandet. Das ganze wird nun für alle folgenden Bytes durchgeführt. Das zweite Byte wird um 16 Stellen nach rechts verschoben, das dritte um 8 Stellen und das letzte Byte um 0 Stellen (wird nicht verschoben). Da wir uns nur für ein Byte interessieren, sollte das Ergbnis der Verschiebung noch bittweise and mit einer Maske verknüpft werden, die nur die ersten 8 Bits gesetzt haben. Diese setzt alle höheren Bits, die nicht zum ersten Byte gehören, auf 0. In C:

1
2
3
4
 
UdpFrame[0] = (Meldungskennung >> 24) & 0x000000FF;
UdpFrame[1] = (Meldungskennung >> 16) & 0x000000FF;
UdpFrame[2] = (Meldungskennung >> 8) & 0x000000FF;
UdpFrame[3] = (Meldungskennung >> 0) & 0x000000FF;
 



In das nächste Byte der UDP Nachricht wird der Wert für DLC geschrieben.

1
 
UdpFrame[4] = Dlc;
 



Und danach kommen die 8 Datenbytes. Auch wenn in der UDP Nachricht immer alle 8 Bytes verschickt werden, reicht es, nur die verwendeten Bytes (DLC) zu kopieren.

1
 
memcpy(&UdpFrame[5], &CanData, Dlc);
 



oder anschaulicher als Schleife:

1
2
3
 
int i;
for (i = 0; i < Dlc; i++)
UdpFrame[5 + i] = CanData[i];
 


st-oldie  
st-oldie
InterRegioExpress (IRE)
Beiträge: 458
Registriert am: 22.12.2009
Homepage: Link
Ort: Friedberg (Hessen)
Gleise Märklin K-Gleis
Spurweite H0
Steuerung Märklin Systems
Stromart Digital


RE: Software schreiben zum steuern von Loks?

#62 von st-oldie , 30.11.2014 23:01

Anhang Teil 1: Aufbau der CAN Nachricht und Abbildung auf eine UDP Sendepuffer

Und nochmals als Zusammenfassung C Code für das Codieren und Decodieren der UDP Nachricht. Es wurde jeweils eine Funktion für Encoder und Decoder geschrieben, damit man sie auch wiederverwenden kann. Die UDP Nachricht belegt immer die maximale Länge, also 4 Byte Meldungskennung, 1 Byte Dlc und 8 Datenytes = 13 Bytes. Selbst wenn die Anzahl benutzter Datenbytes (Wert von Dlc) kleiner ist.

Das Dekodieren des UDP Frames und Zusammenbauen der Meldungskennung ist das Gegenstück zum Verteilen der Meldungskennung auf den UDP Frame. Dazu werden die einzelnen Bytes "in die richtige Position" in dem 32-Bit Integer geschoben und mit bitweisem Oder zusammengeführt. Achtung: Wird eine Variable vom Typ eines 8-Bit Integer (in C ein char) nach links geschoben, "fallen" die Bits nach links raus und das Ergebnis ist 0. Deshalb steht im Beispiel unten zuerst ein cast des Byte auf ein unsigned long vor dem shift. Es kann auch zuerst das Byte´einem unsigned long zugewiesen werden.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 
void DecodeUdp(unsigned long *Id, unsigned char *Dlc, unsigned char *Data,
unsigned char *UdpFrame)
{ int i;
 
*Id = ((unsigned long)UdpFrame[0] << 24) |
((unsigned long)UdpFrame[1] << 16) |
((unsigned long)UdpFrame[2] << 8) |
((unsigned long)UdpFrame[3] << 0);
*Dlc = UdpFrame[4];
for (i = 0; i < 8; i++)
Data[i] = UdpFrame[5 + i];
}
 
void EncodeUdp(char *UdpFrame,
unsigned long Id, unsigned char Dlc, unsigned char *Data)
{ int i;
 
UdpFrame[0] = (Id >> 24) & 0x000000FF;
UdpFrame[1] = (Id >> 16) & 0x000000FF;
UdpFrame[2] = (Id >> 8) & 0x000000FF;
UdpFrame[3] = (Id >> 0) & 0x000000FF;
UdpFrame[4] = Dlc;
for (i = 0; i < 8; i++)
UdpFrame[5 + i] = Data[i];
}
 
int main(void)
{ unsigned long Id;
unsigned char Dlc;
unsigned char Data[8], UdpFrame[13];
 
EncodeUdp(UdpFrame, Id, Dlc, Data);
DecodeUdp(&Id, &Dlc, Data, UdpFrame);
}
 
 



Ein Beispiel in Basic hab ich allerdings nicht erstellt, da ich damit zu wenig Erfahrung habe.


st-oldie  
st-oldie
InterRegioExpress (IRE)
Beiträge: 458
Registriert am: 22.12.2009
Homepage: Link
Ort: Friedberg (Hessen)
Gleise Märklin K-Gleis
Spurweite H0
Steuerung Märklin Systems
Stromart Digital


RE: Software schreiben zum steuern von Loks?

#63 von st-oldie , 30.11.2014 23:05

Hi,

tja, eigentlich wollte ich jetzt auch den Aufbau der Märklin Meldungskennung beschreiben. Und dann hatte mich jemand per Telefon davon abgehalten. Es war noch nicht mal wichtig oder dringend, nur zu lange. Die Meldungskennung kommt dann später.

Vielleicht mag ja jemand eine BASIC Version meines Codes einstellen, da der Threadersteller FreeBasic benutzt.

Tschüß
Michael


st-oldie  
st-oldie
InterRegioExpress (IRE)
Beiträge: 458
Registriert am: 22.12.2009
Homepage: Link
Ort: Friedberg (Hessen)
Gleise Märklin K-Gleis
Spurweite H0
Steuerung Märklin Systems
Stromart Digital


RE: Software schreiben zum steuern von Loks?

#64 von ALWIM , 01.12.2014 00:15

Zitat
Vielleicht mag ja jemand eine BASIC Version meines Codes einstellen, da der Threadersteller FreeBasic benutzt.

Vielleicht schaffe ich es selber, den Quellcode umzuschreiben? Mir fehlt halt nur die Zeit und C-Kenntnisse dafür! Ich komme zur Zeit zu gar nichts. Das einzige was ich für die Modellbahn erledigt habe, war die Bestellung des neuen TGV's. Bis Weihnachten, keine Zeit zu irgendwas in Richtung Programmierung. Leider!

Zitat
Die Meldungskennung kommt dann später.

Kein Problem, eilt ja nicht!

Gruß
ALWIM


Mein letzter Zugang:
1x Lockdown...


ALWIM  
ALWIM
InterRegio (IR)
Beiträge: 219
Registriert am: 05.04.2014


RE: Software schreiben zum steuern von Loks?

#65 von st-oldie , 02.12.2014 00:15

Hallo ALWIM,

Zitat von ALWIM
Vielleicht schaffe ich es selber, den Quellcode umzuschreiben?



Du hast ja schon erfolgreich ein Beispiel umgesetzt. Ich hab mal versucht, den eigentlichen Kern meiner Algorithmen auf BASIC umzusetzen. Leider wieß ich nicht, wie genau man ein Unterprogramm in BASIC erstellt. Ich habe nämlich zum einen Parameter, die verändert werden (unten als output aufgeführt) und Parameter, die nur gelesen werden (input). Und ich weiß nicht, wie ich das in BASIC umsetzen kann.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
 
DIM i AS INTEGER              ' als Laufvariable
DIM Id As ULong ' CAN Id = Meldungskennung, 32 Bits
DIM Dlc AS BYTE ' Anzahl der Datenbytes im CAN-Paket, 1 Byte (eigentlich nur ein Nibble)
DIM Data(0 TO 7) AS BYTE ' array[0..7] of Byte, Datenbytes
DIM UdpFram AS STRING ' diese Zeichenkette werden wir über das UDP-Socket senden
DIM TmpByte AS ULong ' ein Byte aus UdpFrame als Long fuer shift
 
' DecodeUdp
' output: Id, Dlc, Data
' input: UdpFrame
 
' Meldungskennung
TmpByte = ASC(UdpFrame(0)) ' 1. Byte = hoechstes Byte der Id
Id = TmpByte SHL 24;
TmpByte = ASC(UdpFrame(1)) ' 2. Byte
Id = Id OR TmpByte SHL 16;
TmpByte = ASC(UdpFrame(2)) ' 3. Byte
Id = Id OR TmpByte SHL 8;
TmpByte = UdpFrame(3) ' 4. Byte = niederwertigstes Byte
Id = OR TmpByte SHL 0;
' DLC
Dlc = UdpFrame(4)
' Datenbytes
FOR i = 0 TO 7
Data = UdpFrame(i + 5)
NEXT
 

' EncodeUdp
' output: UdpFrame
' input: Id, Dlc, Data
 
'Meldungskennung
UdpFrame = CHR((Id SHR 24) AND &hFF) + CHR((Id SHR 16) AND &hFF)
UdpFrame = UdpFrame + CHR((Id SHR 8) AND &hFF) + CHR(Id AND &hFF)
' DLC
UdpFrame = UdpFrame + CHR(Dlc AND &hFF)
' Datenbytes
FOR i = 0 TO 7
UdpFrame = UdpFrame + CHR(Data(i) AND &hFF)
NEXT
 



Vielleicht hilft das weiter. Wenn jemand das etwas verbessern möchte, kann er das gern hier einstellen. Hier muß es nicht optimiert werden, es soll eher verständlich sein. Ich hab aus dem Encoder und Decoder eine eigene Funktion gemacht, um den Teil besser beim Kodieren der Nachrichten verwenden zu können.

Zitat von ALWIM
Bis Weihnachten, keine Zeit zu irgendwas in Richtung Programmierung.



Das paßt aber mir nicht so schlecht. Ich denke, bis dahin hab ich mal alle Teile beschrieben, so daß du mit den Tests weitermachen kannst und probieren kannst.

Tschüß
Michael


st-oldie  
st-oldie
InterRegioExpress (IRE)
Beiträge: 458
Registriert am: 22.12.2009
Homepage: Link
Ort: Friedberg (Hessen)
Gleise Märklin K-Gleis
Spurweite H0
Steuerung Märklin Systems
Stromart Digital


RE: Software schreiben zum steuern von Loks?

#66 von ALWIM , 02.12.2014 00:34

Zitat
Leider wieß ich nicht, wie genau man ein Unterprogramm in BASIC erstellt.


Aber ich! Habe ja schon mehrfach Unterprogramme in Freebasic erstellt! Genau genommen programmiere ich nur noch mit Unterprogramme!

Zitat
Vielleicht hilft das weiter. Wenn jemand das etwas verbessern möchte, kann er das gern hier einstellen. Hier muß es nicht optimiert werden, es soll eher verständlich sein. Ich hab aus dem Encoder und Decoder eine eigene Funktion gemacht, um den Teil besser beim Kodieren der Nachrichten verwenden zu können.


Das hilft mir sogar sehr weiter! Danke hierfür!!!

Ich habe bereits schon ein funktionsfähiges Programm (selber geschrieben), das bei der Taste S auf Stopp geht und bei der Taste G auf Go bzw. die Leertaste für Stopp und Go! Auf diese Basis möchte ich dann, sofern ich mal Zeit hab, aufbauen.

Gruß
ALWIM


Mein letzter Zugang:
1x Lockdown...


ALWIM  
ALWIM
InterRegio (IR)
Beiträge: 219
Registriert am: 05.04.2014


RE: Software schreiben zum steuern von Loks?

#67 von st-oldie , 07.12.2014 19:18

Hallo ALWIM,

Zitat von ALWIM
Das hilft mir sogar sehr weiter! Danke hierfür!!!



Schön , aber hattest du nicht auch geschrieben, daß du dabei etwas lernen wolltest?

Wenn du nur Code übernimmst, dann lernst du ja nichts dabei. Du kannst hierbei aber folgende lernen:

- zum einen den Aufbau der Märklin CAN Nachrichten. Die sind aber schon in der Märklin Doku ausreichend gut beschrieben.

- dann die Umsetzung der Beschreibung in Code. Deshalb hab ich (im Gegensatz zu Märklin) immer schon geschrieben, daß du den entsprechenden Teil an die gewünschte Position mit Bitshift verschieben mußt und dann mit einer Maske verküpfen mußt, damit nur die gewünschten Bits übrig bleiben. Wenn du das soweit verstanden hast, dann brauchst du keinen Beispielcode sondern kannst die Zeile mit SHR/SHL und OR/AND auch selbst schreiben. Das sind ja immer nur 4 Werte bzw. 4 Bytes, aus denen sich die CAN Id zusammensetzt. Also immer nur 4 Zeilen für Encoder und Decoder. Der einzige Fallstrick ist, wenn du ein Byte (z.b. deinen String) in die richtige Position der Meldungskennung verschieben möchtest. Das jeweils höchstwertige Bit "purzelt" beim Verschieben um eine Stelle nach links aus dem Byte raus.

Tschüß
Michael


st-oldie  
st-oldie
InterRegioExpress (IRE)
Beiträge: 458
Registriert am: 22.12.2009
Homepage: Link
Ort: Friedberg (Hessen)
Gleise Märklin K-Gleis
Spurweite H0
Steuerung Märklin Systems
Stromart Digital


RE: Software schreiben zum steuern von Loks?

#68 von st-oldie , 07.12.2014 19:27

2. Meldungskennung

Märklin benutzt die CAN ID (siehe oben den Hinweis auf die can struct) als Meldungskennung. Die Meldungskennung wird dabei aus verschiedenen Informationen zusammengesetzt.

1
2
3
4
 
32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
/ / / /
Prio Command Resp Hash
 



In den niederwertigsten 2 Byte (16 Bit) steht ein Hashwert. Dieser Hashwert wird über die eigene uid gebildet und soll sicherstellen, daß es keine 2 Teilnehmer mit der gleichen ID gibt. Den Hash bekommt man aus der Meldungskennung, indem die unteren 2 Bytes ausmaskiert werden, also durch eine AND Verknüpfung mit einer Maske, in der die unteren 16 Bit auf 1 gesetzt sind (0x0000FFFF in C).

Anschließend folgt 1 Bit das angibt, ob die CAN Nachricht eine Anforderung oder eine Antwort ist. Wird ein Kommando versendet, ist das Response Bit auf 0 gesetzt. Der Empfänger schickt als Quittung das Kommando mit gesetztem Response Bit zurück. Das Response Bit bekommt man durch Verschieben der Bits nach rechts um 16 Stellen, dadurch landet dieses Bit in der ersten Stelle. Dann muß das Ergebnis der Verschiebung mit einer Maske per AND verknüpft werden, in der nur das unterste Bit gesetzt ist.

Die nächsten 8 Bits sind das Kommando. Wie zu erwarten ist, schiebt man die Bits um 17 Stellen nach rechts und maskiert das unterste Byte aus.

Danach kommen 2 Bits, die die Priorität der Nachricht angeben. Um an die Priorität zu kommen, werden die Bits der Meldungskennung um 25 Stellen nach rechts geschoben und mit einer Maske mit 2 gesetzten Bits verknüpft. Märklin hat für die Priorität die folgenden Werte definiert:

1: Stopp / Go / Kurzschluss-Meldung
2: Rückmeldungen
3: Lok anhalten (?)
4: Lok / Zubehörbefehle

Allerdings hält sich die MS2 nicht an diese Definition. Wenn ich das richtig im Kopf habe, ist die Prio immer auf 0 (auf jeden Fall immer den gleichen Wert) gesetzt.

Um die Meldunggskennung zu erstellen, müssen einfach die einzelnen Komponenten an die ensprechende Stelle nach links verschoben werden und duch eine OR Verknüpfung gesetzt werden. Das funktioniert analog zum Zusammenbau der Meldungskennung aus den Bytes des Strings für den UPD Socket.

Und als C Beispiel:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
void DecodeId(unsigned long CanId, unsigned short *Hash, unsigned short *Response,
unsigned short *Comamnd, unsigned short *Prio)
{
*Hash = (CanId >> 0) & 0x0000ffff;
*Response = (CanId >> 16) & 0x00000001;
*Command = (CanId >> 17) & 0x000000ff;
*Prio = (CanId >> 25) & 0x00000003;
}
 
unsigned long EncodeId(unsigned short Hash, unsigned short Response,
unsigned short Comamnd, unsigned short Prio)
{
return (((unsigned long)Hash << 0) |
((unsigned long)Response << 16) |
((unsigned long)Command << 17) |
((unsigned long)Prio << 25));
}
 



Und als BASIC Schnipsel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 
DIM Hash As UShort            ' der Hashwert
DIM Response As UShort ' das Responsebit
DIM Comamnd As UShort ' das Command Byte
DIM Prio As UShort ' die Prioritaet
DIM Id As ULong ' CAN Id = Meldungskennung, 32 Bits
DIM TmpByte AS ULong ' ein Wert von oben Long fuer shift
 
' DecodeId
' output: Hash, Response, Command, Prio
' input: CanId
Hash = (CanId SHL 0) AND &h0000FFFF;
Response = (CanId SHL 16) AND &h00000001;
Command = (CanId SHL 17) AND &h000000FF;
Prio = (CanId SHL 25) AND &h00000003;
 
' EncodeId
' output: CanId
' input: Hash, Response, Command, Prio
TmpByte = Hash
Canid = TmpByte SHL 0 ' shift kann entfallen, dient nur didaktischen Gruenden
TmpByte = Response
Canid = CanId OR (TmpByte SHL 16)
TmpByte = Command
Canid = CanId OR (TmpByte SHL << 17)
TmpByte = Prio
Canid = CanId OR (TmpByte SHL << 25)
 


st-oldie  
st-oldie
InterRegioExpress (IRE)
Beiträge: 458
Registriert am: 22.12.2009
Homepage: Link
Ort: Friedberg (Hessen)
Gleise Märklin K-Gleis
Spurweite H0
Steuerung Märklin Systems
Stromart Digital


RE: Software schreiben zum steuern von Loks?

#69 von st-oldie , 14.12.2014 23:16

2.1 UID

Jeder Teilnehmer am CAN Protokoll von Märklin hat eine eindeutige Kennung, die UID (Universal ID). Diese UID ist ein 32 Bit Wert. Märklin hat diese Wertebereich aufgeteilt. Die Werte von Hex 0x00000000 bis Hex 0x0000FFFF werden unter anderem dazu benutzt, bestehende Protokolle mit einem festen
Adressbereich einzubinden. Z.B. liegt die UID für die alten Motorola Dekoder mit DIP Schalter, die 80 Adressen kennen und die programmierbaren Motorola Dekoder im Bereich von 0x00000000 und Hex 0x00003FF. Funktionsdecoder liegen im Bereich von 0x00003000 bis 0x000033FF.

Die UID 0x00000000 ist die Broadcast Adresse. Das heißt, wenn als Empfänger diese UID benutzt wird, ist jeder Teilnehmer gemeint.

Leider hat Märklin nicht definiert, wie genau die möglichen Adressen auf ihren Bereich abgebildet werden. Aber Märklin hat 2 Beispiele anfgeführt:

Die 80 Adressen der Motorola Dekoder werden einfach zu dem Anfang von ihrem Bereich addiert. Z.B. wird eine Motorola Adresse von 3 zu der UID 0x00000000 + 2 = 0x00000002. Oder einfacher, die Motorola Adresse ist auch gleichzeitig die UID.

Für die Funktionsdecoder wird zu der Adresse 0x00003000 addiert, was der Anfang dieses Bereichs ist. Z.B. bekommt ein Decoder mit der Adresse 3 die UID 0x00003000 + 3 = 0x00003003

Es kann deshalb angenommen werden, daß generell die Adresse einfach zu der Anfangsadresse des zugehörigen Breichs addiert wird, um die UID zu erhalten.

Der Wertebereich von Hex 0x1800 bis Hex 0x1BFF ist für Privatanwender und Clubs reserviert. D.h., unser Programm sollte eine UID aus diesem Bereich wählen.


st-oldie  
st-oldie
InterRegioExpress (IRE)
Beiträge: 458
Registriert am: 22.12.2009
Homepage: Link
Ort: Friedberg (Hessen)
Gleise Märklin K-Gleis
Spurweite H0
Steuerung Märklin Systems
Stromart Digital


RE: Software schreiben zum steuern von Loks?

#70 von st-oldie , 15.12.2014 00:16

2.2 Hash

Der Hash wird über die UID des Senders gebildet. Dazu werden das obere und das untere Word per XOR verknüpft.

Zusätzlich müssen die Bits 7-9 auf die Werte 110 binär gesetzt werden.

1
2
 
15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  Hash
1 1 0
 



Damit die Berechnung des Hashs anschaulicher wird, werden jetzt im folgenden die Berechnung Schritt für Schritt erklärt.

Das untere Word der UID bekommt man, indem einfach das untere Word ausmaskiert wird. D.h. die UID wird per AND mit einem Wert verknüpft, in dem nur die unteren 16 Bits gesetzt sind:

1
 
UID & 0x0000FFFF
 



Das obere Word erhält man, indem die UID um 16 Bits nach rechts verschoben wird:

1
 
UID >> 16
 



Beide Teile werden per XOR verknüpft:

1
 
(UID & 0x0000FFFF) ^ (UID >> 16)
 



Bit 7 soll den Wert 0 haben, also wird das Ergebnis der XOR Verknüpfung mit einer Mask per AND verknüpft, in der dieses Bit nicht gesetzt ist:

1
 
((UID & 0x0000FFFF) ^ (UID >> 16)) & 0xFF7F
 



Die Bits 8 und 9 sollen den Wert 1 haben. Also wird das Ergebnis per OR mit einer Maske verknüpft, die diese Bits gesetzt haben:

1
 
(((UID & 0x0000FFFF) ^ (UID >> 16)) & 0xFF7F) | 0x0300
 



Und nochmals als Funktion:

1
2
3
4
 
unsigned short CalcHash(unsigned long UID)
{
return (((UID & 0x0000FFFF) ^ (UID >> 16)) & 0xFF7F) | 0x0300;
}
 



Und wozu wird der Hash nun benutzt?

Zum einen dazu, doppelte Adressen zu vermeiden. Wenn ein Teilnehmer am CAN Bus eine Nachricht mit dem eigenen Hash empfängt, muß ein neuer Hash gewählt werden. Was gleichbedeutend dazu ist, eine neue UID zu wählen. Denn es kann sein, daß der andere Teilnehmer die gleiche UID hat. Es kann sein, muß aber nicht. Denn der Wertebereich für die UID sidn 32 Bit, für den Hash 16 Bit. Also können verschiedene UIDs auch zum gleichen Hash führen.

Und dann kann der Hash dazu benutzt werden, die Nachricht von Nachrichten der MS1 zu unterscheiden. Märklin hat ja definiert, daß die Bits 7-9 die Werte 110 binär haben müssen (siehe oben). Und damit auch in der Meldungskennung die Bits 7-9 die Werte 110 binär haben (siehe 2. Mesldungskennung). Diese Bits haben in einer Nachricht der MS1 nienmals diese Werte. Und damit können diese CS2/MS2 Nachrichten von den MS1 Nachrichten unterschieden werden. Wir verknüpfen also einfach den Hash per AND mit einer Maske, die nur diese 3 Bits enthält und können das Ergebnis mit den gewünschten Wert vergleichen:

1
2
3
4
 
int IsCs2Msg(unsigned short Hash)
{
return (Hash & 0x0380) == 0x0300;
}
 



2.2.1 Folgenummer

Werden Daten übertragen, wie z.B. die Loks der MS2 oder die lokomotive der CS2, dann wird anstelle des Hashs die Folgenummer übertragen. D.h. die zu einer Datenübertragung gehörenden Pakete bekommen eine fortlaufende Nummer. Da ja die Bits 7-9 einen definierten Wert haben müssen, werden für die Folgenummer nur 13 Bits benutzt. Die untersten 7 Bits werden in die untersten Bits des Hashwerts geschrieben. Die obersten 6 Bits werden in die obersten Bits des zweiten Bytes des Hash geschrieben. Die folgenden Skizze zeigt, wo die einzelnen Bits der Folgenummer im Hash landen:

1
2
3
4
5
6
7
8
9
10
 
15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0  Hash
1 1 0 |
|
|
|
|
|
|
|
0 0 0 x x x x x x x x x x x x x Folgenummer
 



Und nun das ganze als Algorithmus. Die unteren Bits werden einfach wieder ausmaskiert:

1
 
Folgenummer & 0x007F
 



Die oberen Bits werden auch ausmaskiert und dann um die 3 Stellen nach links verschoben:

1
 
(Folgenummer & 0x1f80) << 3
 



Und dann müssen nur die beiden Werte mit OR zusammen verknüpft werden. Dann müssen nur noch die Bits 7-9 wie oben beschrieben gesetzt werden. Damit ergibt sich der Hash aus der Folgenummer wie folgt:

1
2
3
4
 
unsigned short CalcHashFromFolgenummer(unsigned short Folgenummer)
{
return ((((Folgenummer & 0xfc00) << 3) | (Folgenummer & 0x007F)) & 0xFF7F) | 0x0300;
}
 



Achtung: Märklin hält sich hier nicht unbedingt an die eigene Doku. In der Lokliste der MS2 war keine Folgenummer gesetzt, sondern der Hash hatte den Wert 0. Da damit die Bits 7-9 nicht den Wert 110 binär haben, sind diese Nachrichten nicht als CS2/MS2 Nachrichten erkennbar!


st-oldie  
st-oldie
InterRegioExpress (IRE)
Beiträge: 458
Registriert am: 22.12.2009
Homepage: Link
Ort: Friedberg (Hessen)
Gleise Märklin K-Gleis
Spurweite H0
Steuerung Märklin Systems
Stromart Digital


RE: Software schreiben zum steuern von Loks?

#71 von st-oldie , 21.12.2014 19:12

3. Befehle

Es gibt von Märklin eine größere Anzahl Befehle. Der System Befehl ist wiederum unterteilt in einzelne Unterbefehle. Damit der Umfang nicht alle Grenzen sprengt, wird hier erst einmal nur der Befehl für die
Lokgeschwindigkeit vorgestellt.

3.1 Lok Geschwindigkeit

Der Befehl für die Lokgeschwindigkeit verwendet als Command Wert für die Meldungskennung den Wert 0x04.

Der Befehl benutzt 1 oder 2 Parameter, die auf die 8 CAN Datenbytes verteilt werden müssen.

Der erste Parameter ist die UID der Lok. Die UID ist wie oben erkllärt, ein
nicht vorzeichenbehafteter 4 Byte Wert

Soll die Geschwindigkeit nur abgefragt werden, ist die UID der einzige Parameter. Deshalb hat DLC den Wert 4 denn es werden nur 4 Bytes von den 8 CAN Datenbytes benutzt.

Soll die Geschwindigkeit gesetzt werden, ist der zweite Wert die Geschwindigkeit. Die Geschwindigkeit ist ein nicht vorzeichenbehafteter 2 Byte Wert. Damit hat DLC den Wert 6.

Wie werden nun die Parameter auf die CAN Datenbytes verteilt? Einfach der Reihe nach, wobei wieder mit dem höchtwertigen Byte einer Zahl begonnen wird. Die ersten 4 Bytes der CAN Daten enthalten also die UID, die nächsten 2 Bytes die Geschwindigkeit, wenn die Geschwindigkeit gesetzt werden soll.

Märklin hat dies schön anschaulich skizziert:

1
2
 
data 0        | data 1 | data 2 | data 3       | data 4          | data 5         | data 6 | data 7
High Byte UID | ... Low Byte UID | High Byte Speed | Low Byte Speed | unbenutzt
 



Wie man nun die einzelnen Bytes aud dem unsigned long der UID extrahiert, ist hier schon mehrfach erklärt worden: das höchstwertige Byte bekommt man, indem man die Bits der UID um 24 Stellen nach rechts schiebt. entsprechend das niederwertigste Byte, indem man nicht verschiebt (die Bits stehen schon an der richtigen Stelle!). Das Ergbnis der Schiebeoperation wird noch mit 0xff per bitweisem AND verknüpft, um nur die untersten 8 Bits stehen zu lassen. Das sieht dann als Code in C wie folgt aus:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
void EncodeDataLokQueryGeschwindigkeit(char *Data, unsigned long LokUid)
{
Data[0] = (Uid >> 24) & 0xff;
Data[1] = (Uid >> 16) & 0xff;
Data[2] = (Uid >> 8) & 0xff;
Data[3] = (Uid >> 0) & 0xff;
}
 
void EncodeDataLokSetGeschwindigkeit(char *Data, unsigned long LokUid, unsigned short Speed)
{
Data[0] = (Uid >> 24) & 0xff;
Data[1] = (Uid >> 16) & 0xff;
Data[2] = (Uid >> 8) & 0xff;
Data[3] = (Uid >> 0) & 0xff;
Data[4] = (Speed >> 8) & 0xff;
Data[5] = (Speed >> 0) & 0xff;
}
 



Bem: Den Shift um 0 kann man weglassen, das dient nur zur Verdeutlichung, das nicht verschoben werden muß.

Um die komplette Nachricht mit allen Bytes (Meldungskennung, ...) zu kodieren, kann man die bisher vorgestellten Funktionen entsprechend kombinieren. Zuerst wird die Meldungskennung aus dem Hash, dem Wert 0x04 für das Command und der Priorität 4 erzeugt. Dann werden die Datenbytes aus der Lok UID und der gewünschten Geschwindigkeit gesetzt. Und zum Schluß werden die UDP Bytes aus der Meldungskennung und den CAN Datenbytes mit der Länge 6 (DLC) erzeugt. Das könnte dann wie folgt aussehen. Der Hash wird nicht in dieser berechnet, da er aus der eigenen UID erzeugt wird und sich nicht verändert.

1
2
3
4
5
6
7
8
9
 
void EncodeLokSetGeschwindigkeit(char *UdpFrame, unsigned short Hash, unsigned long LokUid, unsigned short Speed)
{
unsigned long Meldungskennung;
char Data[8];
 
Meldungskennung = EncodeId(Hash, 0, 0x04, 4);
EncodeDataLokSetGeschwindigkeit(Data, LokUid, Speed);
EncodeUdp(UdpFrame, Meldungskennung, 6, Data);
}
 



Das Dekodieren der UID und der Geschwindigkeit aus den CAN Datenbytes erfolgt auch wieder auf die bekannte Art. Jedes Byte wird zuerst in den entsprechenden Datentyp gewandelt (cast in C), damit die Bits beim Verschieben nicht "rauspurzeln" und 0 als Ergebnis geben. Dann werden die Bytes an die gewünschte Position verschoben und per bitweisem ODER miteinander verknüpft. Das sieht dann als C Code wie folgt aus:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
void DecodeDataLokQueryGeschwindigkeit(char *Data, unsigned long *LokUid)
{
*LokUid = ((unsigned long)Data[0] << 24) |
((unsigned long)Data[1] << 16) |
((unsigned long)Data[2] << 8) |
((unsigned long)Data[3] << 0);
}
 
void DecodeDataLokSetGeschwindigkeit(char *Data, unsigned long *Uid, unsigned short *Speed)
{
*LokUid = ((unsigned long)Data[0] << 24) |
((unsigned long)Data[1] << 16) |
((unsigned long)Data[2] << 8) |
((unsigned long)Data[3] << 0);
*Speed = ((unsigned long)Data[4] << 8) |
((unsigned long)Data[5] << 0);
}
 


st-oldie  
st-oldie
InterRegioExpress (IRE)
Beiträge: 458
Registriert am: 22.12.2009
Homepage: Link
Ort: Friedberg (Hessen)
Gleise Märklin K-Gleis
Spurweite H0
Steuerung Märklin Systems
Stromart Digital


RE: Software schreiben zum steuern von Loks?

#72 von st-oldie , 22.12.2014 23:39

4. UID der Lokomotive ermitteln

Um nun eine Lok zu steuern fehlt noch die UID der Lok. Für das Motorola Protokoll ist das einfach. Wie in Teil "2.1 UID" beschrieben, ist die UID die Motorola Adresse. Für MFX ist das nicht so einfach, da sich die Dekoder anmelden und die Adresse von der Zentrale vegeben wird. Allerdings können wir einfach die CS2 fragen. Dazu startet man einen Webbrowser und gibt als URL die folgende Adresse ein:

1
 
http://<ip-adresse-der-cs2>/config/lokomotive.cs2
 



Dabei ist <ip-adresse-der-cs2> durch die IP Adresse der CS2 zu ersetzen. Als Ergebnis bekommt man eine Datei mit allen Informationen der Lokomotiven, die der CS2 bekannt sind. Der Aufbau ist auch in der Märklin Doku beschrieben. Die Datei einthält für jede Lokomotive einen Eintrag, der mit dem Schlüsselwort "lokomotive" beginnt. Die zugehörigen Daten fangen mit Punkten an und bilden dadurch quasi eine Baumstruktur. Dies sieht man an dem Eintrag für die Funktionen, die dazu gehörenden Werte sind mit 2 Punkten versehen. Und wie man sieht, gibt es einen Eintrag ".uid" mit der UID der Lok.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 
lokomotive
.uid=0x4006
.name=212 074-9
.adresse=0x14
.typ=mfx
.sid=0x1
.mfxuid=0x7dfc72f2
.icon=212 074-9
.symbol=11
.av=15
.bv=15
.volume=0
.velocity=0
.richtung=0
.tachomax=320
.vmax=235
.vmin=8
.xprotokoll=0
.mfxtyp=0
.stand=0x0
.fahrt=0x0
.funktionen
..nr=0
..typ=1
..dauer=0
..wert=0
..vorwaerts=0x0
..rueckwaerts=0x0
 


st-oldie  
st-oldie
InterRegioExpress (IRE)
Beiträge: 458
Registriert am: 22.12.2009
Homepage: Link
Ort: Friedberg (Hessen)
Gleise Märklin K-Gleis
Spurweite H0
Steuerung Märklin Systems
Stromart Digital


RE: Software schreiben zum steuern von Loks?

#73 von st-oldie , 22.12.2014 23:53

Hi,

so, jetzt haben wir eigentlich alles zusammen, um eine Lok zu steuern. Das wären:

    - Aufbau des UDP Frames
    - Aufbau der Meldungskennung
    - Aufbau des Hash
    - Aufbau der Datenbytes
    - Ermitteln der UID der Lok


Wer verstanden hat, wie die einzelnen Teile einer Informationseinheit an die richtige Stelle durch Verschieben der Bits gebracht werden, wie einzelne Komponenten durch bitweises OR kombiniert werden und wie durch bitweises AND bestimmte Bits stehen läßt und andere ausblendet, sollte alles auch auf eine Programmiersprache seiner Wahl umsetzen können. Wenn sie Bitoperationen unterstützt. Das ist auch das, was ich mit meiner Erklärung bezwecken wollte. Ich wollte nicht ein Programm zum Abtippen liefern. Sondern man sollte verstehen, wie das Protokoll umzusetzen ist.

Sollten noch Fragen offen sein, einfach hier stellen. Ich kann dann versuchen, sie zu klären.

Ich mach mal über Weihnachten eine kleine Pause. Vielleicht hat danach ja jemand eine eigene Umsetzung gemacht Man kann auch soweit gehen, per http Lib mit dem Programm die "lokomotive.cs2" zu lesen und auszuwerten. Damit läßt sich dann dem User eine Liste der zu steuernden Loks anbieten.

Tschüß
Michael


st-oldie  
st-oldie
InterRegioExpress (IRE)
Beiträge: 458
Registriert am: 22.12.2009
Homepage: Link
Ort: Friedberg (Hessen)
Gleise Märklin K-Gleis
Spurweite H0
Steuerung Märklin Systems
Stromart Digital


RE: Software schreiben zum steuern von Loks?

#74 von ALWIM , 23.12.2014 02:07

Vielen herzlichen Dank für die Antworten!
Sobald ich etwas mehr Zeit habe, lese ich mich in die ganzen Sachen mal genauer ein. Nach Weihnachten vielleicht? Und dann schauen wir mal, was draus wird!



Gruß
ALWIM


Mein letzter Zugang:
1x Lockdown...


ALWIM  
ALWIM
InterRegio (IR)
Beiträge: 219
Registriert am: 05.04.2014


RE: Software schreiben zum steuern von Loks?

#75 von ALWIM , 28.12.2014 17:58

So:
Habe jetzt ein Programm geschrieben, was eine Lok steuern kann!

Im Quellcode steht bisher eine feste IP-Adresse sowie eine feste Lokadresse (Adresse 2) drin. Mit den Pfeiltasten (Pfeil nach oben, Pfeil nach unten) ändere ich die Geschwindigkeit! Mit der Taste S gehe ich auf Stopp. Mit G auf Go.
Im Display der CS 2 ändert sich auch die Grafik! Das heißt die km/h nimmt zu! Wäre eine Lok auf dem Gleis und die CS 2 aktiv, so würde die Lok fahren! Je nach dem wie ich aufdrehe, so schnell fährt die Lok. Da kommt Freude auf!

Jetzt werde ich noch die Richtungsänderung mit einbauen. Dann die Lokfunktionen versuchen. Mal schauen, wo das ganze hinführt und endet! Das Beste ist ja: die Anbindung ist nicht so kompliziert wie bei der CS 2.exe, sondern viel einfacher und sofort da! Ich brauche keinen Neustart eines der Geräte! Man muss nur die Software starten und schon kann man sofort loslegen! Ich weiß nicht, warum das bei der CS 2 PC-Software so schwierig ist? Eigentlich ist es so einfach! Man braucht in meinem Programm nur die richtige IP der CS 2 eingeben, damit alles klappt!

Was ich mich aber noch frage ist? Wie kommt ein Laie bei einer MFX-Lok an die richtige Loknummer wenn in der Bedienungsanleitung zb. 60 drin steht? Ich meine, nicht jeder weiß, dass man mit
http://<ip-adresse-der-cs2>/config/lokomotive.cs2 an die richtige Adresse kommt! Die Zahl, die in der Anleitung drin steht, ist ja dann irgendwie sinnlos? Oder gibt es da eine Formel zum umrechnen? Man müsste die richtige Adresse doch irgendwie auslesen können? Vielleicht hat da einer eine Idee?

Zitat
Exakt das dürfte das Problem sein, dass reines BASIC scheitert. Der CAN-Bus braucht die Daten Bitweise, dazu hat BASIC im Gegensatz z.B. zu C keine Möglichkeit im Sprachumfang.


Mit Qbasic geht es tatsächlich nicht! Ist reines Basic. Da Freebasic aber Bitmanipulation kann, kann man hier nicht mehr von reinem Basic sprechen! Freebasic ist der inoffizielle Nachfolger von Qbasic!

Zitat
C(++) hat halt doch seine Vorteile, gerade wenn's tief runter geht...


Ob C(++) in dem Anwendungsfall noch einen Vorteil hat, wage ich zu bezweifeln? Schneller und leichter als mit Freebasic geht es mit C(++) wahrscheinlich auch nicht? Und bei dem Klammerwirrwarr, nehme ich halt doch lieber eine andere Programmiersprache!

Was mich noch wundert ist:
Gebe ich eine zu hohe Geschwindigkeit an, zeigt die CS 2 eine Fahrstufe von > 800 an! Wahnsinn oder? Aber sonst alles normal! Unglaublich, was die CS 2 alles akzeptiert!

Sollte ich das Programm irgendwann mal irgendwo zum Download anbieten, so läuft das nur auf Windows Rechner! Der Grund dafür ist, dass ich immer die WinApi verwende! Profiprogrammierer wissen was ich meine.

Linux habe ich nicht und Mac kann der Freebasic-Compiler nicht! Somit bleibt sowieso nur Windows übrig!

In diesem Sinne: Wünsche allen eine schöne nachWeihnachtszeit!

Edit:
Ich kann mit Basic mit einfachsten Mitteln das Biospasswort eines Windowsrechners löschen! Dazu genügen 2 Zeilen Code! Da sieht man mal, wozu diese kleine Mistding fähig ist! Und mir wollte einer weis machen das Basic ungeeignet ist, ich auf eine andere Programmiersprache wechseln sollte?

Ob MM oder MFX oder DCC, alle Decoderarten kann ich mit meinem Testprogramm erfolgreich ansteuern!

Gruß
ALWIM


Mein letzter Zugang:
1x Lockdown...


ALWIM  
ALWIM
InterRegio (IR)
Beiträge: 219
Registriert am: 05.04.2014


   


  • Ähnliche Themen
    Antworten
    Zugriffe
    Letzter Beitrag
Xobor Einfach ein eigenes Forum erstellen
Datenschutz