Zum Hauptinhalt springen

LS XGI / XBC / XBM (FEnet) Treiber

Überblick

Kommuniziert mit den PLC-Serien XGI / XBC / XBM von LS ELECTRIC (ehemals LS Industrial Systems) über das Standardprotokoll FEnet (Fast Ethernet).

PunktWert
opc_typeLS
Implementierungsklasseplantpulse.driver.protocol.ls.LSDriver
KommunikationsbibliothekEigene Java-Implementierung (plantpulse-plc-driver-ls.jarFEnetClient)
read
write❌ (im eigenen Java-Treiber ist keine write-API freigegeben)
Sicherheitkeine (Firmennetz vorausgesetzt)
Umstellung nativ → Java

Früher basierte die Anbindung auf NativeProcessDriver: eine in .NET geschriebene externe native Binärdatei (FENetClient.exe) wurde als externer Prozess gestartet. Seit 2025 erfolgt die Umstellung auf eine eigene Java-Implementierung (plantpulse-plc-driver-ls.jar), die direkt per Socket kommuniziert. Dadurch entfallen OS-Abhängigkeiten und der Aufwand für die Verwaltung externer Prozesse.


OPC-Registrierungsformular

FeldBedeutungBeispiel
opc_agent_ipPLC-IP192.168.0.80
opc_agent_portFEnet-Port2004 (XGT-Standard)
timecycleAbfrageintervall (ms)1000
options.company-idFEnet Company ID (optional)(meist leer)
options.use-checksumBCC-Prüfsumme verwendenfalse (default)
options.use-hex-bit-indexBit-Index hexadezimal verwendenfalse (default)
options.connect-timeoutVerbindungs-Timeout (ms)3000
options.read-timeoutread-Timeout (ms)3000

In der connect-Phase wird zuerst eine NetUtils.isReachable(ip)-Ping-Prüfung durchgeführt → bei Nichterreichbarkeit sofortiger Fehlschlag.


Tag-Format plc_address

FEnet-Standard (offizielles Format)

%<DeviceType><DataType><Index>
BeispielBedeutung
%DW00309Data-Bereich, Word, Index 309
%DD00600Data-Bereich, Double Word (32 Bit), Index 600
%DL00800Data-Bereich, Long Word (64 Bit), Index 800
%MX02704Memory-Bereich, Bit, Index 0x2704 (oder dezimal 2704)
%MW00100Memory-Bereich, Word, Index 100

DeviceType-Buchstaben: D (Data), M (Memory), K (Keep), F (Flag), T (Timer), C (Counter), R usw. — die Standard-Gerätecodes von LS XGI.

DataType-Buchstaben: X (Bit), B (Byte), W (Word, 16 Bit), D (Double Word, 32 Bit), L (Long Word, 64 Bit).

Edge Short Form (empfohlen)

Edge akzeptiert die Short Form und wandelt sie automatisch in den FEnet-Standard um.

Edge-Eingabedata_typeformatErgebnis der automatischen Umwandlung
D00309Integer(empty)%DW00309
D00600IntegerDW%DD00600
D00800Long(empty)%DL00800
M02704Boolean(empty)%MX02704
D00100FloatREAL (oder default)%DD00100
D00200DoubleLREAL%DL00200
D00300StringSTR[10]10 Worte read ab %DW00300

Interne Implementierung (LSDriver.toFEnet):

// raw plc_address (D00309) → %D<dataCh>00309
static String toFEnet(String rawAddr, char dataCh) {
if (rawAddr.charAt(0) == '%') return rawAddr; // 이미 표준이면 유지
return "%" + Character.toUpperCase(rawAddr.charAt(0)) + dataCh + rawAddr.substring(1);
}

dataCh wird durch data_type und format bestimmt (siehe nächster Abschnitt).


Zuordnung data_type / format (Details)

Der LS-Treiber erlaubt es, bei gleicher Short Address allein über format die Speicherbreite explizit zu ändern, sodass ein Gerätecode frei auf 16/32/64 Bit abgebildet werden kann.

Integer-Familie (data_type=Integer / Short / Int / Int16 …)

formatBedeutungBreiteFEnet DataTypeAufruf
(empty)Word (signed)16 Bit%DWclient.readWord
UI / UW / UWORDUWord (unsigned)16 Bit%DWclient.readUWord
DW / DWORD / DOUBLE_WORDDWord (signed)32 Bit%DDclient.readDWord
UL / UDW / DUW / UDWORDUDWord (unsigned)32 Bit%DDclient.readUDWord
LW / LWORD / LONG_WORDLWord (signed)64 Bit%DLclient.readLWord
ULW / ULWORDULWord (unsigned)64 Bit%DLclient.readULWord
Bedeutung eines nicht angegebenen format

D00309 + data_type=Integer + format= (leer) bedeutet 16-Bit signed Word. Wird 32 Bit benötigt, ist format=DW explizit anzugeben. Das entspricht der üblichen Konvention von LS XGI.

Float / Double

data_typeformatBreiteFEnetAufruf
Float / REAL(empty) / REAL / FLOAT32 Bit IEEE 754%DDclient.readFloat
Double / LREAL(empty) / LREAL / DOUBLE64 Bit IEEE 754%DLclient.readDouble

Auch bei format=DW + data_type=Float wird als 32-Bit-Float interpretiert (Verzweigung isFloat(dt)).

Boolean

data_typeformatBedeutung
Boolean / Bool / Bit(empty) / X / BITbitweiser read von %MX... oder %PX...

Short Form unverändert: M02704%MX02704.

String

formatBedeutungBreite
STR1 Wort (2 Zeichen)16 Bit × 1
STR[N]N Worte (2N Zeichen)16 Bit × N

ASCII-Kodierung + low byte first (LS-Spezifikation). Abschließende NUL-Bytes werden getrimmt.

// readStringMulti: N 워드 연속 read, low byte 먼저
for (int i = 0; i < wordCount; i++) {
int w = client.readUWord("%" + dev + "W" + (startIdx + i));
bytes[b++] = (byte) (w & 0xFF);
bytes[b++] = (byte) ((w >> 8) & 0xFF);
}

BIN / BIN[idx]

Liest ein Wort und extrahiert nur Bit idx (gleiche Konvention wie bei Modbus).

formatVerhalten
BINWort read, dann Bit 0 extrahieren
BIN[5]Bit 5 extrahieren
BIN[F]Bit hex F (=15) extrahieren (bei einem Zeichen ist Hex zulässig)

Häufige Fehler + Behebung

Meldung / SymptomUrsacheBehebung
LS-PLC Ping failed : <ip>ICMP nicht erreichbarKabel/Firewall prüfen. Bei ICMP-Block-Umgebung Sperrrichtlinie überprüfen
LS connect failedFEnet-Modul nicht aktiv / Port-MismatchIn XG5000 IP/Port des FEnet-Moduls prüfen (meist 2004)
Wert ist immer 0Short Form → Breiten-Mismatch (Word, aber als DWord gelesen)format leer lassen oder mit DW exakt angeben
32-Bit-Float fehlerhaftformat fehlt → wird als Word gelesendata_type=Float + format=REAL angeben
Zeichenkette verfälschtLS low-byte-first nicht berücksichtigtEdge übernimmt das automatisch. Vorsicht bei externer Byte-Interpretation
Bit wird nicht gelesenShort Form landet als D00100M02704 (M-Bereich) verwenden oder format=BIN[idx]

curl-Registrierungsbeispiel

Beispiel mit gemischten D- und M-Bereichen von XGI / XBC / XBM:

curl -X POST http://<edge-host>/api/v1/opc \
-H "Content-Type: application/json" \
-d '{
"opc_id": "OPC_LS_XBM_0001",
"opc_type": "LS",
"opc_name": "XBM Line A",
"opc_agent_ip": "192.168.0.80",
"opc_agent_port": "2004",
"site_id": "SITE_00001",
"auto_collect": true,
"timecycle": 1000,
"options": {
"connect-timeout": "3000",
"read-timeout": "3000",
"use-checksum": "false"
},
"tag_list": [
{
"tag_id": "OPC_LS_XBM_0001_TAG_00001",
"tag_name": "Counter",
"plc_address": "D00309",
"data_type": "Integer"
},
{
"tag_id": "OPC_LS_XBM_0001_TAG_00002",
"tag_name": "Production32",
"plc_address": "D00600",
"data_type": "Integer",
"format": "DW"
},
{
"tag_id": "OPC_LS_XBM_0001_TAG_00003",
"tag_name": "Pressure",
"plc_address": "D00100",
"data_type": "Float",
"format": "REAL"
},
{
"tag_id": "OPC_LS_XBM_0001_TAG_00004",
"tag_name": "Status",
"plc_address": "M02704",
"data_type": "Boolean"
},
{
"tag_id": "OPC_LS_XBM_0001_TAG_00005",
"tag_name": "BatchName",
"plc_address": "D00500",
"data_type": "String",
"format": "STR[10]"
},
{
"tag_id": "OPC_LS_XBM_0001_TAG_00006",
"tag_name": "Bit3OfStatus",
"plc_address": "D00400",
"data_type": "Integer",
"format": "BIN[3]"
}
]
}'

Wert read:

curl -s http://<edge-host>/api/v1/tag/OPC_LS_XBM_0001_TAG_00003/value | jq

Hinweise zum Verhalten

  • Priorität der Read-Verzweigung (LSDriver.read()):
    1. data_type=String oder format ist STR / STR[N]readStringMulti
    2. format ist BIN oder BIN[idx] → Wort read, dann Bit extrahieren
    3. Explizite format-Verzweigung (UI, DW, UL, LW, REAL, LREAL usw.) → readByFormat
    4. Fallback: data_type allein (readByDataType)
  • Der Aufruf client ist synchronized, daher erfolgt der read mehrerer Tags einer OPC seriell. Andere OPCs laufen in eigenen Threads.
  • write ist nicht implementiert. Für die Nutzung von Sparkplug NCMD muss künftig FEnetClient.write* freigegeben werden.

Beispielsammlung (nach Datentyp)

Alle im Betrieb von LS XGI / XBC / XBM häufig verwendeten Kombinationen in einer Tabelle. plc_address bezieht sich auf die Short Form und wird automatisch in die %D...-Standardnotation umgewandelt.

Bit / Boolean

data_typeformatplc_addressSpeicherbreiteBedeutung / Anmerkung
Boolean(empty)M027041 BitBit im Memory-Bereich. Häufigste Form
Boolean(empty)P0001F1 BitHexadezimaler Bit-Index von LS XGI (F=15). Bei use-hex-bit-index=true
Boolean(empty)K000101 BitKeep-Relay-Bit
Boolean(empty)T01101 BitTimer-Ausgangsbit
BooleanBIND0030916 Bit → Bit 0Wort read, dann Bit 0 extrahieren
BooleanBIN[3]D0030916 Bit → Bit 3Bit 3 extrahieren
BooleanBIN[F]D0030916 Bit → Bit 15Hex-Index F=15

16-Bit-Ganzzahl (Integer/Word)

data_typeformatplc_addressSpeicherbreiteBedeutung
Integer(empty)D0030916 Bitsigned Word (%DW00309)
IntegerUID0030016 BitUWord (unsigned, client.readUWord)
IntegerUWORDD0030016 Bitidentisch mit UI

32-Bit-Ganzzahl (DWord)

data_typeformatplc_addressSpeicherbreiteBedeutung
IntegerDWD0060032 BitDWord signed (Kombination %DD00600, D00600/00601)
IntegerDWORDD0060032 Bitwie oben
IntegerDUWD0069032 BitUDWord (unsigned 32)
IntegerUDWD0069032 Bitidentisch mit UDW
IntegerULD0069032 BitULong = UDWord (Alias)

64-Bit-Ganzzahl (LWord)

data_typeformatplc_addressSpeicherbreiteBedeutung
Long(empty)D0070064 BitLWord signed (%DL00700)
LongLWD0070064 Bitexplizites LWord
LongLWORDD0070064 Bitidentisch
LongULWD0075064 BitULWord (unsigned 64)

Gleitkomma (Float / Double)

data_typeformatplc_addressSpeicherbreiteBedeutung
Float(empty)D0045032 BitIEEE 754 single (%DD00450)
FloatREALD0045032 Bitexplizit
FloatDWD0045032 BitVerarbeitung als float über Verzweigung isFloat(dt)
DoubleLREALD0050064 BitIEEE 754 double (%DL00500)
Double(empty)D0050064 Bitidentisch mit LREAL

Zeichenkette (String)

data_typeformatplc_addressSpeicherbreiteBedeutung
StringSTRD0080316 Bit (1 Wort)2 chars (low byte first)
StringSTR[5]D0080080 Bit (5 Worte)10 chars, NUL-Trim
StringSTR[10]D00500160 Bit (10 Worte)20 chars
StringSTR[16]D0010032 Worte32 chars (32 Byte) — von XGI empfohlene Ausrichtung

Einsatz von Formeln (LS-Praxismuster)

Zweckdata_typefomulaEingabe → Ausgabe
Integer-Rohwert → 1 NachkommastelleFloat${VALUE}*0.11638163.8
Integer-Rohwert → 2 NachkommastellenFloat${VALUE}*0.0112345123.45
signed 16 → unsigned UmwandlungInteger${VALUE}+65536Korrektur negativer Rohwerte (16-Bit-Umrechnung)
Nullpunktkorrektur (anderes Tag)Float${VALUE}-${TAG_ZERO}1024 - 24 = 1000
Kalibrierung (gain × x + offset)Float${VALUE}*${TAG_GAIN}+${TAG_OFFSET}Korrekturkoeffizienten als eigenes Tag
Hz-Umrechnung (rpm → Hz)Float${VALUE}/60180030.0

Details zur Verwendung von Formeln siehe Formel-Referenz.

Umfassendes curl-Beispiel (alle Typen auf einmal)

curl -X POST http://<edge-host>/api/v1/opc \
-H "Content-Type: application/json" \
-d '{
"opc_id": "OPC_LS_FULL",
"opc_type": "LS",
"opc_name": "LS XGI Full",
"opc_agent_ip": "192.168.0.80",
"opc_agent_port": "2004",
"site_id": "SITE_00001",
"auto_collect": true,
"timecycle": 1000,
"options": { "use-hex-bit-index": "true" },
"tag_list": [
{"tag_id":"OPC_LS_FULL_T01", "tag_name":"BitM", "plc_address":"M02704", "data_type":"Boolean"},
{"tag_id":"OPC_LS_FULL_T02", "tag_name":"BitPHex", "plc_address":"P0001F", "data_type":"Boolean"},
{"tag_id":"OPC_LS_FULL_T03", "tag_name":"WordSigned", "plc_address":"D00309", "data_type":"Integer"},
{"tag_id":"OPC_LS_FULL_T04", "tag_name":"WordU", "plc_address":"D00300", "data_type":"Integer", "format":"UI"},
{"tag_id":"OPC_LS_FULL_T05", "tag_name":"DWordS", "plc_address":"D00600", "data_type":"Integer", "format":"DW"},
{"tag_id":"OPC_LS_FULL_T06", "tag_name":"DWordU", "plc_address":"D00690", "data_type":"Integer", "format":"DUW"},
{"tag_id":"OPC_LS_FULL_T07", "tag_name":"LWord", "plc_address":"D00700", "data_type":"Long"},
{"tag_id":"OPC_LS_FULL_T08", "tag_name":"Real", "plc_address":"D00450", "data_type":"Float", "format":"REAL"},
{"tag_id":"OPC_LS_FULL_T09", "tag_name":"LReal", "plc_address":"D00500", "data_type":"Double", "format":"LREAL"},
{"tag_id":"OPC_LS_FULL_T10", "tag_name":"Str1Word", "plc_address":"D00803", "data_type":"String", "format":"STR"},
{"tag_id":"OPC_LS_FULL_T11", "tag_name":"Str10Word", "plc_address":"D00500", "data_type":"String", "format":"STR[10]"},
{"tag_id":"OPC_LS_FULL_T12", "tag_name":"BitOfWord", "plc_address":"D00309", "data_type":"Boolean", "format":"BIN[3]"},
{"tag_id":"OPC_LS_FULL_T13", "tag_name":"PressScale", "plc_address":"D00100", "data_type":"Float", "format":"REAL", "fomula":"${VALUE}*0.1"}
]
}'