1 Naposledy upravil: dockys (2021-01-22 07:42:27)

Téma: [vyřešeno] Modbus TCP a chyba -3

Dobrý den,
měl bych dotaz ohledně Modbus TCP na zařízení SDS-BIG.
Mám tento kód, který mi v pravidelných intervalech načítá data z FVE Victron přes Modbus TCP.

Jenomže vždy po nějakém čase (cca 2 dny) se stane to, že mi to přestane fungovat s chybou -3. Tím pádem každé další volání končí chybou -3 a jediné co v danou chvíli můžu udělat je, že musím restartovat SDS, pak to zase funguje.
Dočetl jsem se v návodu, že se jedná o chybu, kdy se volá nějaká Modbus funkce dříve, něž byla dokončena předchozí.
Vycházel jsem ze vzorového programu ze stránky http://wiki.merenienergie.cz/index.php/MODBUS_TCP, jen jsem kód trochu upravil.

Pravděpodobně nemám ošetřené všechny návratové hodnoty z volání funkce SDS_get_i32(12400) nebo SDS_get_i32(12404), ale nevím jaké. Neřešil někdy někdo něco podobného?

Pozn.
Napadla mě teď jedna věc, pokud by volání funkce modbus_tcp_read() skončilo s chybou, nedojde k zavolání funkce modbus_tcp_disconnect(), tím pádem při dalším zavolání funkce modbus_tcp_connect() to vrací vlastně -3, protože teoreticky by měl být stále připojen.


int readModbusTest() {
    int error;
    
    //pripojeni
    modbus_tcp_connect(MODBUS_SERVER_IP[0], MODBUS_SERVER_IP[1], MODBUS_SERVER_IP[2], MODBUS_SERVER_IP[3], MODBUS_SERVER_PORT, 0);
    while(1) {
        error = SDS_get_i32(12400);        
        if(error < 0) {
            printf("Chyba modbus_tcp_connect: %i\n", error);
            return error;
        }
        
        if(error == 2) break;
    }
    
    modbus_tcp_read(242, 0x04, 4, 36);
    while(1) {
        error = SDS_get_i32(12404);
        if(error < 0) {
            printf("Chyba modbus_tcp_read: %i\n", error);
            return error;
        }
        
        if(error == 0) break;
    }
    
    inNapetiL1 = SDS_get_i32(12470);
    inNapetiL2 = SDS_get_i32(12471);
    inNapetiL3 = SDS_get_i32(12472);
    inProudL1 = SDS_get_i32(12473);
    inProudL2 = SDS_get_i32(12474);
    inProudL3 = SDS_get_i32(12475);
    inFreqL1 = SDS_get_i32(12476);
    inFreqL2 = SDS_get_i32(12477);
    inFreqL3 = SDS_get_i32(12478);
    
    //odpojeni
    modbus_tcp_disconnect();
    while(1) {
        error = SDS_get_i32(12400);
        if(error < 0) {
            printf("Chyba modbus_tcp_disconnect: %i\n", error);
            return error;
        }
        
        if(error != 4) break;
    }
    
    return 0;
}

2

Re: [vyřešeno] Modbus TCP a chyba -3

zkuste to dle původního příkladu

 modbus_tcp_read(242, 0x04, 4, 36);

 while (SDS_get_i32(12404) == 256) { ; };

 if (SDS_get_i32(12404) != 0) return error;

dále sem zkuste (v době kdy to selže jak popisujete) přepsat obsah stránky "192.168.1.250/cgi_mbtc" (ip adresa samozřejmě podle vaší konfigurace), uvidíme co se dozvíme

Pochlubte se - popište jak využíváte své zařízení SDS zde ! Můžete si bezplatně přidat svou reklamu !

3

Re: [vyřešeno] Modbus TCP a chyba -3

Díky, upravil jsem program a nechám to běžet a uvidí se.

Btw. Zkoušel jsem ještě udělat ještě to, že v podstatě zavolám po sobě 2x funkci  modbus_tcp_connect(), poprvé se připojí, to je OK a při druhém volání, když je spojení aktivní, tak mi je vrácena právě ta hodnota -3. To by simulovalo případ, kdy během volání funkce modbus_tcp_read() dojde k chybě, po chybě je tam return.. tím pádem nedojde k zavolání funkce modbus_tcp_disconnect() a při dalším vyčítání dat mi je právě vrácena chyba -3, a tak pořád dokola..

4

Re: [vyřešeno] Modbus TCP a chyba -3

Upravil jsem program, ale stejně to taky udělalo. Vidím asi problém v tom, jak jsem psal níže, že modbus_tcp_read() skončí chybou a v programu zůstane "otevřené" připojení k modbus serveru, pak další pokud o připojení skončí chybou -3.
Tady je vypis z dane URL:

 MODBUS TCP CLIENT
connection: 192.168.48.51 : 502v
keepalive: runs 166000 msec
con: c:1 fcs:0
fcget: -3 -2 -2 -2 -6 -2 -2 -2 -2 api_tout=42 msg_tout=0
TCP TX: tosend=12 left=0 sentmsg=0x04
sm: act=4 in-st=512
msg TX: uid=100 tid=65536 addr=817
msg RX: uid=100 tid=65535 addr=840 tstamp=68936110 quantity=5

RX DATA get:
[12470] = 502
[12471] = 116
[12472] = 582
[12473] = 82
[12474] = 1
[12475] = 0
[12476] = 0
[12477] = 0
[12478] = 0
[12479] = 0
[12480] = 0
[12481] = 0
[12482] = 0
[12483] = 0
[12484] = 0
[12485] = 0
[12486] = 0
[12487] = 0
[12488] = 0
[12489] = 0
[12490] = 0
[12491] = 0
[12492] = 0
[12493] = 0
[12494] = 0
[12495] = 0
[12496] = 0
[12497] = 0
[12498] = 0
[12499] = 0
[12500] = 0
[12501] = 0
[12502] = 0
[12503] = 0
[12504] = 0
[12505] = 0
[12506] = 0
[12507] = 0
[12508] = 0
[12509] = 0
[12510] = 0
[12511] = 0
[12512] = 0
[12513] = 0
[12514] = 0
[12515] = 0
[12516] = 0
[12517] = 0
[12518] = 0
[12519] = 0
[12520] = 0
[12521] = 0
[12522] = 0
[12523] = 0
[12524] = 0
[12525] = 0
[12526] = 0
[12527] = 0
[12528] = 0
[12529] = 0
[12530] = 0
[12531] = 0
[12532] = 0
[12533] = 0
[12534] = 0
[12535] = 0
[12536] = 0
[12537] = 0
[12538] = 0
[12539] = 0
[12540] = 0
[12541] = 0
[12542] = 0
[12543] = 0
[12544] = 0
[12545] = 0
[12546] = 0
[12547] = 0
[12548] = 0
[12549] = 0
[12550] = 0
[12551] = 0
[12552] = 0
[12553] = 0
[12554] = 0
[12555] = 0
[12556] = 0
[12557] = 0
[12558] = 0
[12559] = 0
[12560] = 0
[12561] = 0
[12562] = 0
[12563] = 0
[12564] = 0
[12565] = 0
[12566] = 0
[12567] = 0
[12568] = 0
[12569] = 0
[12570] = 0
[12571] = 0
[12572] = 0
[12573] = 0
[12574] = 0
[12575] = 0
[12576] = 0
[12577] = 0
[12578] = 0
[12579] = 0
[12580] = 0
[12581] = 0
[12582] = 0
[12583] = 0
[12584] = 0
[12585] = 0
[12586] = 0
[12587] = 0
[12588] = 0
[12589] = 0
[12590] = 0
[12591] = 0
[12592] = 0
[12593] = 0
[12594] = 0
[12595] = 0
[12596] = 0
[12597] = 0
[12598] = 0
[12599] = 0
[12600] = 0
[12601] = 0
[12602] = 0
[12603] = 0
[12604] = 0
[12605] = 0
[12606] = 0
[12607] = 0
[12608] = 0
[12609] = 0
[12610] = 0
[12611] = 0
[12612] = 0
[12613] = 0
[12614] = 0
[12615] = 0
[12616] = 0
[12617] = 0
[12618] = 0
[12619] = 0
[12620] = 0
[12621] = 0
[12622] = 0
[12623] = 0
[12624] = 0
[12625] = 0
[12626] = 0
[12627] = 0
[12628] = 0
[12629] = 0
[12630] = 0
[12631] = 0
[12632] = 0
[12633] = 0
[12634] = 0
[12635] = 0
[12636] = 0
[12637] = 0
[12638] = 0
[12639] = 0
[12640] = 0
[12641] = 0
[12642] = 0
[12643] = 0
[12644] = 0
[12645] = 0
[12646] = 0
[12647] = 0
[12648] = 0
[12649] = 0
[12650] = 0
[12651] = 0
[12652] = 0
[12653] = 0
[12654] = 0
[12655] = 0
[12656] = 0
[12657] = 0
[12658] = 0
[12659] = 0
[12660] = 0
[12661] = 0
[12662] = 0
[12663] = 0
[12664] = 0
[12665] = 0
[12666] = 0
[12667] = 0
[12668] = 0
[12669] = 0
[12670] = 0
[12671] = 0
[12672] = 0
[12673] = 0
[12674] = 0
[12675] = 0
[12676] = 0
[12677] = 0
[12678] = 0
[12679] = 0
[12680] = 0
[12681] = 0
[12682] = 0
[12683] = 0
[12684] = 0
[12685] = 0
[12686] = 0
[12687] = 0
[12688] = 0
[12689] = 0
[12690] = 0
[12691] = 0
[12692] = 0
[12693] = 0
[12694] = 0
[12695] = 0
[12696] = 0
[12697] = 0
[12698] = 0
[12699] = 0
[12700] = 0
[12701] = 0
[12702] = 0
[12703] = 0
[12704] = 0
[12705] = 0
[12706] = 0
[12707] = 0
[12708] = 0
[12709] = 0
[12710] = 0
[12711] = 0
[12712] = 0
[12713] = 0
[12714] = 0
[12715] = 0
[12716] = 0
[12717] = 0
[12718] = 0
[12719] = 0

5

Re: [vyřešeno] Modbus TCP a chyba -3

Podle výpisu, v okamžiku tohoto problému, vrací 12404 hodnotu -6, což by mělo být oblsouženou správným způsobem ve full-c programu, ideálně výpisem chybové hlášky do konzole a zavoláním odpojení (disconnect).

Dále, ještě nedoběhl "api timeout" (dle výpisu zbývá 42 sekund), jakmile doběhne do nuly a přitom je systém v nesprávném stavu (např. aktuální situace) tak práve po doběhnutí do nuly dojde k "resetu" modbus tcp klienta a měl by být zase plně použitelný.

dockys napsal:

vidím asi problém v tom, jak jsem psal níže, že modbus_tcp_read() skončí chybou a v programu zůstane "otevřené" připojení k modbus serveru, pak další pokud o připojení skončí chybou -3.

Nejprve je potřeba zavolat disconnect, je-li otevřené připojení, a až pak v takové situaci lze zavolat connect.

To je přesně důvod proč opakované volání connect vrací -3, no není to přesná chybová hodnota (tento detail upravím), ale je to chybová hodnota a nic to nemění na tom, že connect nelze volat na "spojené spojení" (je to TCP spojení a to trvá než se určeným způsobem ukončí), takže nejprve je potřeba se odpojit přes disconnect. Pokud dojde k rozpadu spojení (např. výpadek sítě), pak to spojení SDS prohlásí za ztracené ale až po uplynutí určitého timeoutu, a podle všeho ve svém FC programu voláte connect dříve, než tento timeout vypršel.

Aktuální FW už rozlišuje chybu -7 (zavedeno toto nové chybové číslo).

Pochlubte se - popište jak využíváte své zařízení SDS zde ! Můžete si bezplatně přidat svou reklamu !

6 Naposledy upravil: dockys (2021-02-01 08:23:58)

Re: [vyřešeno] Modbus TCP a chyba -3

Tak problém s chybou -3 jsem opravil, v podstatě šlo jen o chybu programátora a příkazy pro Modbus funkce byly volány v nesprávném pořadí smile

Ale vyskytl se mi další problém, souvisí to nejspíše tady s tím, co jsme řešili.
Dělá to zase vždy až po nějaké době běhu.
Jde o to, že program se připojí k Modbus serveru (pokud není připojen), to proběhne OK.
Další krok je volání funkce modbus_tcp_read() a následně čekací cyklus while (SDS_get_i32(12404) == 256) { ; };, který čeká cca 72 vteřin (API timeOut) a poté skončí s chybou -2, potažmo -6.
A takto se to chová už pořád, do restartu SDS, potom vše zase jede nějakou dobu.
Nejspíše dojde k chybě komunikace mezi SDS a Modbus serverem a i když mám oštetřené chybové stavy a volám disconnet a znovu connect, tak to skončí v tomto stavu a nejde z něho ven.

Ve výpisu stránky jsou vidět stavy "fcget:", kdy se mění první hodnota na 2,4,0,1,2, takže dojde ke korektnímu odpojení a znovu připojení, jakmile doběhne timeOut.
Ale při modbus_tcp_read() to prostě nikdy neskončí jiným stavem, než 256 a následně chyba, kdy dojde timeOut.

Program mám upravený, aby zůstalo otevřené spojení k Modbus server, ale dělalo to, i když jsem se na žačátku připojil a na konci odpojil.

Na videu je vidět okamžik, kdy skončí API timeOut, dojde k odpojení a připojení a skočí to zase do stavu 256, ve kterém to již zůstane. Firmware mám (Beta 27.1.2021), ale dělalo to i v posledním "stable".
Odkaz na video

int vysledek, lastError;
unsigned int lastMillisModbus, start, cas;
int inVykonL1, inVykonL2, inVykonL3;
int outVykonL1, outVykonL2, outVykonL3;

void loop() {
    if(SDS_get_u32(3) - lastMillisModbus >= 500) {
        lastMillisModbus = SDS_get_u32(3);
        
        start = SDS_get_u32(3);
        
        vysledek = readModbus();
        
        cas = ((SDS_get_u32(3) - start) * 10);
        
        if(lastError != vysledek || vysledek < 0) {
            lastError = vysledek;
            
            printf("Modbus TCP vysledek: %i, cas: %ims\n", vysledek, cas);
        }
    }
}

int readModbus() {
    int error;

    //test na pripojeni
    if(SDS_get_i32(12400) != 2) {
        modbus_tcp_connect(192, 168, 10, 12, 9999, 0);
        while(1) {
            error = SDS_get_i32(12400);

            if(error < 0) {
                if(error == -7) {
                    modbusDisconnect();
                }
                return error;
            }

            if(error == 2) break;
        }
    }
    
    error = readModbusData(100, 817, 6);
    if(error != 0) return error;
    
    outVykonL1 = SDS_get_i32(12470);
    outVykonL2 = SDS_get_i32(12471);
    outVykonL3 = SDS_get_i32(12472);

    inVykonL1 = SDS_get_i32(12473);
    inVykonL2 = SDS_get_i32(12474);
    inVykonL3 = SDS_get_i32(12475);
    
    error = readModbusData(242, 3, 36); 
    if(error != 0) return error;
    
    error = readModbusData(243, 776, 14); 
    if(error != 0) return error;
    
    error = readModbusData(225, 259, 8); 
    if(error != 0) return error;
    
    error = readModbusData(100, 840, 5); 
    if(error != 0) return error;
    
    return 0;
}

int readModbusData(unsigned int id, unsigned int address, unsigned int length) {
    modbus_tcp_read(id, 0x04, address+1, length);
    
    while (SDS_get_i32(12404) == 256) { ; };

    if(SDS_get_i32(12404) != 0) {
        modbusDisconnect();
        return SDS_get_i32(12404);
    }
    return 0;
}

void modbusDisconnect() {
    modbus_tcp_disconnect();
    while(1) {
        if(SDS_get_i32(12400) != 4) break;
    }
}

void main(void) {
    lastError = 999999;
    
    while(1) {
        loop();
    }
}

Máte prosím ještě nějaký nápad, co dělám špatně, popř. co by se s tím dalo dělat?

7

Re: [vyřešeno] Modbus TCP a chyba -3

Opět, potřebuji vidět obsah webové stránky /cgi_mbtc v okamžiku kdy je to zaseknuté (čeká na ten timeout).
Tím se zjistí, v jakém kroku došlo k "záseku" komunikace.

V době kdy to vrací 256 tak SDS provádí komunikace přes tcp se serverem. Odešle dotaz a čeká na odpověď, kterou zpracuje. Potom se 256 změní na specifické číslo výsledku činnosti. Pokud se kdykoliv v tom procesu stane chyba, zůstane tam 256 až do timeoutu (nebo se ihned ukončí s jiným chybovým číslem -X, pokud je takové definováno). Nicméně ten timeout je obvykle z příčiny rozpadu síťové komunikace.

Pochlubte se - popište jak využíváte své zařízení SDS zde ! Můžete si bezplatně přidat svou reklamu !

8 Naposledy upravil: dockys (2021-02-01 11:20:16)

Re: [vyřešeno] Modbus TCP a chyba -3

Poslal jsem Vám SZ s přístupem přímo na dané SDS.

9

Re: [vyřešeno] Modbus TCP a chyba -3

Přístup asi nepomůže, neuvidím tam nic víc než co vy - potřebuji aby jste sebral obsah webové stránky /cgi_mbtc a dal ji sem, z toho už dokážu zjistit ve kterém kroku se to zaseklo. A od toho se odpíchnu dále. Určitě se to musí dořešit do konce, tohle je první podstatný krok.

Pochlubte se - popište jak využíváte své zařízení SDS zde ! Můžete si bezplatně přidat svou reklamu !

10

Re: [vyřešeno] Modbus TCP a chyba -3

MODBUS TCP CLIENT
connection: 192.168.48.51 : 502
keepalive: runs 571500 msec
con: c:1 fcs:0
fcget: 2 -2 -2 -2 256 -2 -2 -2 -2 api_tout=29 msg_tout=43000
TCP TX: tosend=12 left=0 sentmsg=0x04
sm: act=8 in-st=512
msg TX: uid=100 tid=66908 addr=817
msg RX: uid=100 tid=65535 addr=840 tstamp=66117138 quantity=5

RX DATA get:
[12470] = 494
[12471] = 65532
[12472] = 65517
[12473] = 81
[12474] = 0

Po dojetí "api_tout" do hodnoty 72 dojde k odpojení od Modbus serveru, znovu připojení a po zavolání prvního požadavku na modbus_tcp_read() tam je stále hodnota 256, která tam je těch 72 sekund a tak pořád dokola až do restartu SDS. Pak to zase šlape.

11

Re: [vyřešeno] Modbus TCP a chyba -3

Nejprve:

TCP TX: tosend=12 left=0 sentmsg=0x04

Bylo odesláno 12 bajtů surové MODBUS TCP zprávy (všechno se povedlo odeslat na server zbývá totiž 0) typu 0x04.
Zatím vše OK.

Ovšem potom:

sm: act=8 in-st=512

Je to ve stavu "waiting for ack (8)" a  "PDU data drop (512)", což znamená, že ze serveru přišla poškozená (neplatná) odpověď, která nesouhlasí s normou určující protokol MODBUS TCP - proto SDS odpověď musí zahodit.
Zdá se že ošetření tohoto stavu bude potřeba zlepšit, což se teď hned udělá.

Řešeno v už vydaném FW.

Pochlubte se - popište jak využíváte své zařízení SDS zde ! Můžete si bezplatně přidat svou reklamu !

12

Re: [vyřešeno] Modbus TCP a chyba -3

Bohužel se to stalo znovu.

connection: 192.168.48.51 : 502
keepalive: runs 594500 msec
con: c:1 fcs:0
fcget: 2 -2 -2 -2 256 -2 -2 -2 -2 api_tout=6 msg_tout=66000
TCP TX: tosend=12 left=0 sentmsg=0x04
sm: act=8 in-st=512 dropr=00000004
RAW-TCP-RX(15): 03 80 00 00 00 0F 64 04 0C 05 00 00 84 00 D7 
msg TX: uid=100 tid=66432 addr=817
msg RX: uid=100 tid=65535 addr=840 tstamp=65633515 quantity=5

RX DATA get:
[12470] = 500
[12471] = 13
[12472] = 64
[12473] = 83
[12474] = 1
[12475] = 0

13

Re: [vyřešeno] Modbus TCP a chyba -3

1) díky za test - výsledek:

Ano, vidím tam jeden problém (TX TID překračuje 16bit rozsah, to bude chyba SDS).

To je vyřešeno ve vydaném oficiálním FW.


2) doplňující informace

Je potřeba se odpojit a počkat, až doběhne odpojování, před tím než se váš FC program pokusí znovu připojit.

 printf("odpojuji...");
 modbus_tcp_disconnect();
 while (SDS_get_i32(12400) == 4) { ; };
 printf(" odpojeno\n");

Odpojování trvá klidně i 20 sekund, to nezávisí na SDS ale čisté na vlastnostech TCP protokolu a také na serveru, jak rychle spojení po požadání na své straně uzavře.

Také, pokud modbus_tcp_connect() vrátí -7 (sys 12400) tak je vhodné právě zavolat ten disconnect a počkat (dokud je tam 4) a pak znovu zkusit ten connect.

Pochlubte se - popište jak využíváte své zařízení SDS zde ! Můžete si bezplatně přidat svou reklamu !

14

Re: [vyřešeno] Modbus TCP a chyba -3

Nahrál jsem nový FW, budu to sledovat a dám vědět.
Prozatím děkuji..

15

Re: [vyřešeno] Modbus TCP a chyba -3

Po skoro třech dnech to prozatím jede bez problému, takže nechci to zakřiknout, ale myslím, že problém vyřešen.. Ještě jednou děkuji!