Prosíme přihlašte se nebo zaregistrujte.

Přihlašte se svým uživatelským jménem a heslem.
Vaše pomoc je stále potřeba!

Autor Téma: Logování sériového portu do MySQL  (Přečteno 4220 krát)

timmynovak

  • Aktivní člen
  • *
  • Příspěvků: 300
Logování sériového portu do MySQL
« kdy: 04 Listopadu 2012, 08:00:37 »
Ahoj, u jsem to zde kdysi okrajově řešil, ale teď je to trochu v jiné situaci (bohužel ani tehdy to nebylo uspokojivě vyřešeno, ale snad nyní...). Už jsem nad tím strávil mnoho večerů, ale bez úspěšně. O co jde. Mám MCU, který mi přes sériovou linku do počítače posílá nějaká data - zprávy v průměru dlouhé cca 70 bajtů, několikrát do minuty, někdy velmi rychle za sebou, někdy s prodlevou minuta. A tato data potřebuji uložit do mysql, každou zprávu samostatně.

Pokud použiji v terminálu cat /dev/ttyS0, vše je v pořádku a žádná data se nikdy neztratila. Pokud je chci jakkoli zpracovávat, počítač nestíhá data ze sériového portu číst a dochází k jejich ztrátám. I třeba jen v situaci, kdy to echem zpětně vypisuji (tedy vůbec nedochází ještě k zápisu do db). S stty jsem už tak zžitý, že jej znám snad do detailu, ale ani to řešení nepřineslo. Co jsem už zkusil:

1. různé nastavení přenosové rychlosti
2. různé stopbity a počet bitů včetně parity
3. zpracování v shellu stylem while read /dev/ttyS0 i cat /dev/ttyS0|while read apod.
4. využití logtty
5. využití céčka, kde jsem v prg nastavil buffer od 256 až po 1024, ale také to nepomohlo (kód viz níže), zkoušel jsem od výpisu do souboru až po výpis na terminál
6. různé kombinace rour s využitím mkfifo

Nemáte někdo nějaké řešení? Už nevím kudy kam, nemyslím si, že je to HW problém, protože těch dat zase tak moc přeneseno není a tohle přece počítače zvládat musí... Jsem si vědom, že dělám někde chybu, ale už nevím kde:( Na Google jsem našel pár podobných dotazů, ale uspokojivé řešení nikde. UART podle mne data přijme, jádro taky, ale aplikačka je nestihne načíst, tak se začnou v bufferu jádra přepisovat či ztrácet.. Podstatnou indicií je, že při pouhém cat do terminálu je vše zcela OK.

Kód: [Vybrat]
    #include <stdio.h>   /* Standard input/output definitions */
    #include <string.h>  /* String function definitions */
    #include <unistd.h>  /* UNIX standard function definitions */
    #include <fcntl.h>   /* File control definitions */
    #include <errno.h>   /* Error number definitions */
    #include <termios.h> /* POSIX terminal control definitions *///Spousta includů

#define BUFSIZE 512
char buf[BUFSIZE];

int main(int argc, char ** argv) {
        int count;
        int port = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
        int log = open("/serial.log",O_CREAT | O_WRONLY | O_APPEND);
        while (1) {
                count = read(port,buf,BUFSIZE);
                write(log,buf,count);
        }
        return 0;
}



timmynovak

  • Aktivní člen
  • *
  • Příspěvků: 300
Re:Logování sériového portu do MySQL
« Odpověď #1 kdy: 20 Listopadu 2012, 14:08:54 »
tak jsem trochu pokorčil a stabilní řešení jsem našel v tom, že do souboru mám přesměrovaný cat sériového portu a cílový soubor sleduji přes tail, který má přesměrovaný výstup do skriptu čtoucího řádek po řádku a zapisujícího do mysql. Zatím žádný výpadek.

Myrmica

  • Závislák
  • ***
  • Příspěvků: 1701
    • MYRMICA
Re:Logování sériového portu do MySQL
« Odpověď #2 kdy: 20 Listopadu 2012, 15:51:13 »
Já bych to řešil speciálním prográmkem. Podle mé představy by měl dva thready, jeden by přijímal data ze seriové linky a posílal je do fronty druhému (hlavnímu) threadu. Ten by je načetl a uložil do databáze. Pokud by tok dat průměrně nepřekračoval rychlost zápisu do databáze, tak by to fungovalo bez problémů. To si ale mohu dovolit jako programátor. :-)
Tvoje řešení má také svůj půvab :-)
Stolní strojek: OS– UBUNTU 16.04 x86_64, MB ASUS P8 Z68-V/GEN3, Intel® Core™ i5-3470 CPU @ 3.20GHz × 4 , 16GiB DDR3, GeForce GTX 670...
Notebook: ASUS U53Jc OS– UBUNTU 16.04 x86_64, Windows 7, Processor – Intel Core i5-460M (2,53 GHz), Graphics – switchable NVIDIA GeForce 310M and Intel GMA HD

timmynovak

  • Aktivní člen
  • *
  • Příspěvků: 300
Re:Logování sériového portu do MySQL
« Odpověď #3 kdy: 20 Listopadu 2012, 16:00:25 »
no ono by to právě asi nefungovalo, viz příklad v c, kdy již nestíhal zápis do souboru. Chápu, že v druhém vlákně mohu mít klidně větší buffer, ale asi i ten by se jednou zaplnil;-) V každém případě neříkám, že mé řešení je ideální, je to takový prasopes:)

Myrmica

  • Závislák
  • ***
  • Příspěvků: 1701
    • MYRMICA
Re:Logování sériového portu do MySQL
« Odpověď #4 kdy: 20 Listopadu 2012, 16:58:08 »
Záleží na rychlosti toku dat, pokud je tok dat nižší než rychlost zápisu, pak to musí fungovat, a záleží jen na konkrétní realizaci. Pokud je tok dat vyšší pak to může fungovat jen do naplnění bufferu. Pokud Ti to nefungovalo v c, a pomocí tvého scriptu ano, pak byl nejspíše problém v nevhodně navrženém prográmku v c.
Stolní strojek: OS– UBUNTU 16.04 x86_64, MB ASUS P8 Z68-V/GEN3, Intel® Core™ i5-3470 CPU @ 3.20GHz × 4 , 16GiB DDR3, GeForce GTX 670...
Notebook: ASUS U53Jc OS– UBUNTU 16.04 x86_64, Windows 7, Processor – Intel Core i5-460M (2,53 GHz), Graphics – switchable NVIDIA GeForce 310M and Intel GMA HD

timmynovak

  • Aktivní člen
  • *
  • Příspěvků: 300
Re:Logování sériového portu do MySQL
« Odpověď #5 kdy: 21 Listopadu 2012, 09:58:56 »
nevím, prográmek je přiložen, možná je špatně. v každém případě to beru jako řešení z nouze cnost a pořád bych to rád udělal stoprocentně dobře. udivuje mne, že toto skoro nikdo neřešil, rpotože to zase IMHO tak nezvyklá věc není.

Myrmica

  • Závislák
  • ***
  • Příspěvků: 1701
    • MYRMICA
Re:Logování sériového portu do MySQL
« Odpověď #6 kdy: 21 Listopadu 2012, 10:49:37 »
No C není zrovna moje doména, ale co koukám na ten tvůj prográmek, tak sice pěkně otevíráš soubor open, ale co ho i zavřít close. Do souboru se dokončí zápis až při jeho zavření. Zkus si projít internet a hledat téma c zápis do souboru.

No a ten cyklus zápisu bych upravil nějak takhle: (nejsem c-čkař, a dělám to z hlavy, mouhou tam být chyby, ale myšlenka je doufám jasná)
Kód: [Vybrat]
int main(int argc, char ** argv) {
        int count;
        int port = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
        while (1) {
                count = read(port,buf,BUFSIZE);
                if (count > 0) {
                        int log = open("/serial.log",O_CREAT | O_WRONLY | O_APPEND);
                        write(log,buf,count);
                        close(log);
                }
        }
        return 0;
Jo a pozor na přístupová práva, pro zápis do "/serial.log" budeš asi potřebovat práva root, dej ho raději třeba do svého domácího adresáře "~/serial.log". Pro přístup k seriovému portu musíš být buď root, nebo členem skupiny dialout (což mi přijde lepší a bezpečnější).
No možná by jsi tam mohl i vložit nějakou podmínku, jak cykl ukončit nebo na chvíli pozastavit, aby jsi si mohl prohlédnout logovací soubor. Při prohlížení souboru během funkce tvého programu, by mohlo dojít k jeho pádu.
Stolní strojek: OS– UBUNTU 16.04 x86_64, MB ASUS P8 Z68-V/GEN3, Intel® Core™ i5-3470 CPU @ 3.20GHz × 4 , 16GiB DDR3, GeForce GTX 670...
Notebook: ASUS U53Jc OS– UBUNTU 16.04 x86_64, Windows 7, Processor – Intel Core i5-460M (2,53 GHz), Graphics – switchable NVIDIA GeForce 310M and Intel GMA HD

timmynovak

  • Aktivní člen
  • *
  • Příspěvků: 300
Re:Logování sériového portu do MySQL
« Odpověď #7 kdy: 21 Listopadu 2012, 11:29:28 »
ad zavírání - ten soubor je otevřen pořád, protože to běží 24x7, měl jsem v c ale i variantu s otevřením a zavřením. Ale to bylo ještě horší, protože data ze sériového portu proudídocela rychle a úž to fakt nestíhalo. A tam si myslím, že je principiální problém.
ad práva - toto mi v tento moment naprosto nevadí, v reálu to běží v konektextu uživatele, toto byly testy
ad prohlížení souboru - k tomu v reálu nikdy nedojde, protože cílem je co nejrychleji všechna příchozí data odhrnout do mysql. Pokus přes soubor byl jen jedním z mnoha. Ideálně by se mi líbilo v c prg, který bude neustále číst a jakýkoli přijatý řádek pošle do databáze. Jenže to jsme tam, kde jsme byli - tj. zápis je tak pomalý, že se prostě některá data ztratí. A zatím jediné funkční řešení je to, co jsem popsal s využitím tailu. Asi si zkusím víc pohrát s variantou dvou samostatných prg, jeden s fakt velkým bufferem a druhý postupně přebírající a volající zápis do db.

Myrmica

  • Závislák
  • ***
  • Příspěvků: 1701
    • MYRMICA
Re:Logování sériového portu do MySQL
« Odpověď #8 kdy: 21 Listopadu 2012, 12:51:42 »
Jáká je reálná rychlost toku dat? Píšeš, že několikrát za minutu. Dejme tomu 10x to je 70x10 = 700 byte za minutu. Myslím, že při téhle rychlosti stačí program otevřít a zavřít soubor aniž by přetekl některý z bufferů (pokud soubor není extrémě veliký třeba desítky MB).

Jakou máš nastavenou rychlost komunikace? Chtělo by to použít minimálně 9600 bódů, ale raději víc. Při 700 bytech za minutu to je 1 start bit, 8 bitů dat, 1 bit parita, 1 stop bit, to je jedenáct bitů na jeden byte. 700x11=7700 bódů. Takž těch 9600 bódů je opravdové minimum rychlosti pro tato data. Raději bych použil 19200 bódů.

Pokud to nestíhá, máš někde chybu v programu nebo MCU. Máš aktivovaný nějaký Flow control? To by mohlo pomoci... (třeba XON XOFF, musí ho však podporovat i mcu)

Zpráva, kterou ti posílá MCU má určitě nějaký formát. Optimalizuj příjem dat a ukládej na disk (do databáze) jen kompletní zprávu. Tím zmenšíš množství otevírání a zavírání souborů či přístupů k databázi.
Kontrolou formátu zprávy, můžeš přesněnji určit, kde dochází k chybě způsobující ztrátu dat.

Možná bych tu zprávu místo do souboru posílal do terminálu. Pokud má nějakou strukturu, mohl by jsi hned vidět, kde se data ztrácejí. Mohl by jsi na terminá vypisovat chybová hlášení...


ad zavírání mít soubor stále otevřený je pěkné, ale nesmysl. Dokud je soubor otevřený pro zápis, obvykle k němu není přístup a pokus o jeho čtení buď skončí chybou nebo přečtený obsah je neúplný.
Takže ten tvuj prográmek je hezký, ale nemá výstup. Je to jako, když napíšeš dopis, nevhodíš ho do schránky a pak se divíš, že ho příjemce nedostal.
Stolní strojek: OS– UBUNTU 16.04 x86_64, MB ASUS P8 Z68-V/GEN3, Intel® Core™ i5-3470 CPU @ 3.20GHz × 4 , 16GiB DDR3, GeForce GTX 670...
Notebook: ASUS U53Jc OS– UBUNTU 16.04 x86_64, Windows 7, Processor – Intel Core i5-460M (2,53 GHz), Graphics – switchable NVIDIA GeForce 310M and Intel GMA HD

timmynovak

  • Aktivní člen
  • *
  • Příspěvků: 300
Re:Logování sériového portu do MySQL
« Odpověď #9 kdy: 21 Listopadu 2012, 13:25:32 »
cca 1000 bajtů za minutu, ale jsou tam náhodné sekvence, čili klidně i dalších 100 bajtů ve chvíli, kdy se zapisuje. Také jsem nečekla, že to bude problém, ale byl. Rychlost je 9600, 8 bitů, bezparitní, 1 stopbit. S tím si zkusím pohrát, to je velmi dobrá myšlenka. říkal jsem si, že čím rychleji budu přenášet, tím rychleji se buffer zaplní:) Asi zcela chybná úvaha.

Řízení toků není žádné.

K chybě dochází jednoznačně ve chvíli, kdy program na pc nestihne příjmout data, viz když dám čistý cat sériového portu, je to zcela OK a k žádné chybě nedojde. Do databáze se vždy zapisuje celý řádek, takže tam počt nijak nezměním.

Ad terminál - no právě, tam k žádnému problému nedojde.

Ad otevřený soubor - mne ani tak nevadí, že se to nepromítne hned, hlavně aby se něco neztratilo a holt by se to do db zapsalo až ve chvíli, kdy dojde k přepsání bufferu. A byl to jak píši jen pokus, kdy už jsem nevěděl kudy kam a opakovaný open s close to zpomalovalo nadpříliš. A hlavně 2. - soubor byl celkově jako přístup jen další pokus, klidně bych se rád bez něj obešel.

Zatím závěr pro mne: zkusím vyšší rychlost komunikace s využitím dvou programů, jeden přijímající data a druhý zapisující do dtb. To, že nyní nevím jak to udělat je jen technický problém:)

Myrmica

  • Závislák
  • ***
  • Příspěvků: 1701
    • MYRMICA
Re:Logování sériového portu do MySQL
« Odpověď #10 kdy: 21 Listopadu 2012, 14:15:24 »
Tak trochu kecám, rychlost přenosu v bódech je rychlost přenosu dat za vteřinu, ne za minutu.
Takže na tisíc byte za minutu potřebuješ minimální rychlost: 1000/60*11=183 bódů.
Omlouvám se za mystifikaci. Nějak jsem to s tema minutama popletl.
Jinak počítej s tím, že zápis do databáze může být pomalejší než zápis do souboru.
Stolní strojek: OS– UBUNTU 16.04 x86_64, MB ASUS P8 Z68-V/GEN3, Intel® Core™ i5-3470 CPU @ 3.20GHz × 4 , 16GiB DDR3, GeForce GTX 670...
Notebook: ASUS U53Jc OS– UBUNTU 16.04 x86_64, Windows 7, Processor – Intel Core i5-460M (2,53 GHz), Graphics – switchable NVIDIA GeForce 310M and Intel GMA HD

jmp

  • Host
Re:Logování sériového portu do MySQL
« Odpověď #11 kdy: 21 Listopadu 2012, 14:28:50 »

timmynovak

  • Aktivní člen
  • *
  • Příspěvků: 300
Re:Logování sériového portu do MySQL
« Odpověď #12 kdy: 21 Listopadu 2012, 14:43:29 »
Jinak počítej s tím, že zápis do databáze může být pomalejší než zápis do souboru.
no to vím, proto jsem postupně šel od nejnáročnějšího k méně náročnému:)

Myrmica

  • Závislák
  • ***
  • Příspěvků: 1701
    • MYRMICA
Re:Logování sériového portu do MySQL
« Odpověď #13 kdy: 21 Listopadu 2012, 19:43:46 »
patrně jde o Baudy?
http://cs.wikipedia.org/wiki/Baud
Jasně, jenže mě kdosi na průmce mě to učil psát to česky, a nějak se toho nemohu zbavit :-D.
Stolní strojek: OS– UBUNTU 16.04 x86_64, MB ASUS P8 Z68-V/GEN3, Intel® Core™ i5-3470 CPU @ 3.20GHz × 4 , 16GiB DDR3, GeForce GTX 670...
Notebook: ASUS U53Jc OS– UBUNTU 16.04 x86_64, Windows 7, Processor – Intel Core i5-460M (2,53 GHz), Graphics – switchable NVIDIA GeForce 310M and Intel GMA HD

 

Provoz zaštiťuje spolek OpenAlt.