Pomoć u projektu (realtime simulator)

poruka: 9
|
čitano: 1.608
|
moderatori: Lazarus Long, XXX-Man, vincimus
1
+/- sve poruke
ravni prikaz
starije poruke gore
14 godina
neaktivan
offline
Pomoć u projektu (realtime simulator)

Pozdrav, imam jedan problem u C#, naime trebam snimiti odredene podatke sa nekih senzora u realnom vremenu gdje zapisujem u .txt datoteku 

timestamp (HH:mm:ss.fff) te nakon toga odredeni tip podataka ali stvar je u tome da ja to moram reproducirati natrag (slicno kao kad snimite video, pa mozda nakon mj dana stisnete play)

ali da sve bude "u realnom" vremenu (tocno po time stampu, znaci ako je jedan podatak zapisan u npr. 12:00:00.000 a drugi u 12:00:00:002 onda se tako trebaju podaci i reproducirati, odnosno slati sa racunala na jedan drugi uredaj).

 

Kako to napraviti pošto ne mogu koristiti timere je Windowsi sami po sebi nisu realtime OS !?

Hvala :)

Moj PC  
0 0 hvala 0
11 godina
offline
Pomoć u projektu (realtime simulator)

Neće ti raditi stabilno niti čitanje niti reprodukcija.

Osim ako znaš kako pečirati NT kernel da radi ono što inače radi za IEEE 1588 pakete (https://en.wikipedia.org/wiki/Precision_Time_Protocol).

 

Prvo ograničenje koje imaš je rezolucija koju procesi "vide" kao rezoluciju sistemskog sata (iako to nije 100% točna definicija)

Ukratko - na nekim mašinama System.Threading.Thread.Sleep(1) traje 15, na nekima oko 10ms, a na nekima je neka vrijednost između.

 

Ako i uspiješ natjerati neki od timera da radi s rezolucijom višom od toga

https://msdn.microsoft.com/en-us/library/windows/hardware/dn265247%28v=vs.85%29.aspx

nema nikakve garancije da će se eventi uvijek hendlati u roku i na vrijeme.

 

Čak i ako nađeš neki savjet, to u praksi pada u vodu kada neki od procesa zakuca CPU ili disk na 100% (npr. oštećena Windows update baza podataka).

Na desktop OS-evima nema nikakve garancije po pitanju determinizma. Točka.

 

Ako nije nekakva primjena gdje je bitna sigurnost i ako se ne razumiješ u elektroniku, uzmi nekakvo mini-računalo, na njemu digni neki ne-desktop OS koji se može natjerati da radi s rezolucijom 1 ms i to je to. Podatke prima na jedan ulaz, dodaje timestamp, prema tebi priča preko mreže, ti mu daješ podatke i timestamp-predefiniranu pauzu između slanja paketa.

E, da, kada ti sve proradi, onda ćeš se možda gnjaviti s latencijama i jitterom na komunikacijskom kanalu (podaci u FIFO i iz FIFO-a neće uvijek ići van točno u mikrosekundu), no to je jednostavniji dio priče.

 

 

 
1 0 hvala 1
14 godina
neaktivan
offline
Re: Pomoć u projektu (realtime simulator)

Zahvaljujem na odgovoru i jasno mi je to sve, ali cuo sam price da bi se to moglo navodno "while" petljom nekako ispisivati npr te razlike od 1ms itd ako je to uopce moguce,

npr u stream readeru (u C#) da ima jos jedna while petlja koja iskreno nemam pojma sto radi (tako su mi na poslu rekli) pa me zanima da li stvarno se moze time to kako odraditi ili ne?

11 godina
offline
Re: Pomoć u projektu (realtime simulator)

Daj molim te pitaj ih na što su to točno mislili. To me stvarno, ali stvarno zanima.

 

Razumno napisan članak:

http://www.codeproject.com/Articles/98346/Microsecond-and-Millisecond-NET-Timer

Uzmi kod i testiraj, naučiti ćeš dosta toga o današnjim mašinama.

Natjeraj da radi, zatim skini neku od onih aplikacija na kojima možeš opterećivati procesor po želji, ili napravi .NET GUI aplikaciju s beskonačnom petljom bez sleepa i u kojoj se ne poziva DoEvents().

 

Prije podosta godina radio sam (poluuspješno) na nečemu u .NET-u što je trebalo komunicirati u periodima kraćim od 10ms.

Testiranjem sam zaključio da serijski port ugrađen na matičnoj ploči reagira puno brže (povremeno reda veličine par ms brže) od onih koji dolaze na raznoraznim I/O karticama. Nije imalo veze s kvalitetom drivera hardwarea.

A razlika u odnosu na raznorazne USB adaptere je bila i više nego očita.

Pokušavao sam dizati i prioritet procesa, refaktorirati kod da radi brže (keširanje podataka, izbjegavanje pristupanja na disk), no uvijek kada bi se mašina opteretila počeo bi raditi nestabilno.

I šećer na kraju:

http://www.sparxeng.com/blog/software/must-use-net-system-io-ports-serialport

Jedino što radi donekle stabilno na tom g*ovnetu od klase je ReadByte() metoda, dakle, moraš napisati svoj wrapper oko toga i izbjegavati sve evente iz te klase.

I dodati hendlanje IOExceptiona, jer MSDN dokumentacija nije baš uvijek potpuna.

 

Na kraju sam to sve prebacio u vanjsku elektroniku baziranu na 8-bitašu.

 

Desktop i serverski OS-evi dolaze podešeni tako da najviše resursa daju aplikacijama.

To znači - kada kreneš žešće sa I/O prometom (disk, mreža), scheduler će prebacivati kontekst na manje predvidljiv način.

Onaj primjer sa CodeProjecta gore raditi će sve dok ne počneš npr. transferirati ogromnu fajlu preko FTP-a dok ti istovremeno npr. Win8 rošta po disku jer radi periodičko održavanje sustava.

 

A onda dolaze i čudne odluke dizajnera i još čudniji fičri u samim OS-ovima

Ovaj komad C# koda:

 

DateTime stamp=DateTime.Now()

Console.Write("\a");

TimeSpan ts=DateTime.Now()-stamp;

 

na WinXP izvršava se oko 70 do 100ms, a na Win7 i kasnijim treba mu obično manje od 1 ms.

Na XP-u ponaša se kao u doba DOS-a (beep piezo zvučnika na matičnoj ploči, odrađuje se sinhrono), dok na novima to ide na zvučnu karticu (asinhrona operacija).

Na single-core mašini (stari celeron) na WinXP ako sam dovoljno puta i dovoljno brzo pozivao taj "\a" ubacivao je male pauze u slanje podataka preko mreže.

14 godina
neaktivan
offline
Pomoć u projektu (realtime simulator)

Pa meni su rekli kao nakon sto se snime podaci s odredenog uredaja (ne mogu govoriti o cemu se radi u detalje jer sam potpisao izjavu o privatnosti podataka), ja bih trebao napraviti aplikaciju u C# u kojoj postoji "Play" tipka gdje se ti podaci znači ponovno isčitaju iz .txt datoteke i nakon toga računalo simulira taj isti uređaj (tj. ako su podaci s tog uređaja poslani na PC u razmaku od 1 ms, PC to mora isto poslati na jedan drugi uređaj).

 

Možda je malo nerazumno napisano pa ću još pojasniti:

 

Znači, inače bi to trebalo funkcionirati ovako:

 

Uređaj1 -> Uređaj2 (bez PC) (tako je taj elektronički dio zamišljen)

 

e, sad, trenutno što ja radim je ovo:

 

Uređaj1 -> PC

a, nakon toga bi trebalo biti ovako

PC -> Uređaj2

 

ako me kuzis, svrha toga sto radim je to da mogu simulirati realne uvjete na PC-u (tj "playati" na drugi uredaj) nakon što se jedanput podaci snime da se ne mora stalno izlaziti na teren

 

E sad, posto su oni svjesni (ja radim par mjeseci tek tamo i nemam toliko iskustva) da na windowsima 1ms je nemoguce postici, a za threadove i slicne stvari

nitko ne garantira da ce se slijedno izvršiti da je to moguce postici while petljom (nemam pojma sto je to trebalo znaciti) i jos uvijek mi je nejasno, a nisu mi imali vremena neki dan

objasniti jer su bili u zurbi tako da jos uvijek taj dio nisam ni zavrsio.

 

Edit:

 

ovako podaci izgledaju snimljeni na PC sa uređaja:

 

(primjer (znaci prva stvar je timestamp HH:mm:ss.fff, ostalo je nebitno )

14:45:55:331;10;506;505;479;53,13009
14:45:55:332;10;509;505;480;63,43493

14:45:55:334;10;508;502;479;53,13001
14:45:55:337;10;508;503;480;63,43492

 

 

 

 

Poruka je uređivana zadnji put uto 31.5.2016 14:48 (NiGHT_RiDER92).
Moj PC  
0 0 hvala 0
11 godina
offline
Pomoć u projektu (realtime simulator)

OK, pošto nije nešto što ide u daljnju prodaju, rješenje može biti i nešto priručno.

 

Kada su u pitanju serijski podaci, brzina njihovog putovanja preko žice je ((1/baudrate)*broj bitova podatka+start bit+stop bit <1 ili više>+paritet <ako se koristi>).

Npr. za za jedan byte na 9600 bit/s to je oko 1.04ms s jednim stop bitom i bez pariteta.

To će ti definirati koliko brzo moraš čitati podatke.

Pošto su u pitanju nekakvi senzori, oni najvjerojatnije trebaju još neko dodatno vrijeme za generiranje podataka i pripremu za slanje, ali tebe treba zanimati kojom brzinom mogu stizati podaci.

 

Najprije bih napravio software na Windowsima u C# s primjerom za timere s CodeProject-a i isključio bih dolazni FIFO buffer na serijskom portu. Tako ćeš izgubiti podatke koje ne stigneš obraditi, no pošto ti software neće ispravno raditi, vidjeti ćeš gdje, što i kako treba ispraviti. S uključenim FIFO bufferom primiti ćeš sve podatke, ali timestamp neće biti ispravan, jer ne znaš koliko dugo podaci sjede u bufferu.

Ako imaš pristup mjernoj opremi, uzmi nekakav logički analizator ili osciloskop, tako da možeš vidjeti kada stvarno podaci idu preko žice, a kada ih ti detektiraš.

 

Za rješenje bih odabrao jedan od ova dva načina:

 

1. Nešto tipa jednostavna i jeftina Arduino elektronika, ali bez njihovog softverskog bloata.

Kristal na 14.7456MHz ili 18.432MHz, tako da možeš bez grešaka pokriti što više raspoloživih brzina komunikacije.

Ako sam ispravno razumio, trebati ćeš jedan port i nekakvu komunikaciju prema PC-u (USB).

Posao te elektronike je da čita port (obavezno preko interrupta), daje timestamp (najbolje nekakav 16-bit timer kao baza za generiranje nekakvog kvazi-sistemskog sata, ali s rezolucijom debelo ispod 1ms), zatim trpa podatke (strukture) u nekakav FIFO i šalje ih na PC. U obrnutoj situaciji uzima podatke s PC-a na nekakav FIFO i šalje na port s pauzama između podataka koje ti definiraš.

U C-u ili C++ to je 200-tinjak linija koda.

Software na PC-u u tom slučaju ne bi ovisio o rezolucijama, timerima, scheduleru, itd...

 

 

2. Nekakav stari desktop ili nekakvo mini-računalo. Digneš na tome neku minimalnu Linux distribuciju bez desktop sučelja.

Svojoj aplikaciji (jer radi s portom) postaviš najviši prioritet procesa.

Instaliraj mono ako želiš raditi software pomoću C#, no pošto nisam koristio u monou timere, ne mogu ti garantirati utječe li još neki faktor na njihovu preciznost.

Što se tiče OS-a, morao bi potestirati dvije situacije - jedna je kernel skompajliran s postavkom CONFIG_HIGH_RES_TIMERS, druga je s CONFIG_HZ_1000=y.

Ako ne želiš raditi sa C#, opet u C ili C++ to nije puno koda.

Za prijem trebaš jedan thread (ili proces) koji radi s portom, dodaje timestamp (u C ili C++ timestamp uzima preko gettimeofday()) i trpa podatke u nekakvu listu/queue.

Drugi thread (ili proces) radi sporije i uzima podatke s liste i šalje ih u nekakvu fajlu/bazu/socket.

Rad s diskovima ili bazama je puno, puno sporija operacija od rada s portom.

Pri predaji trebao bi imati listu koju nahraniš s vremenima slanja paketa, timer koji postavljaš ovisno o tome kolike su pauze između slanja i kada timer opali staviš podatak na port.

U ovom slučaju ne preporučujem korištenje USB-to-serial adaptera, jer neki imaju velike latencije između prijema podatka preko žice i isporuke OS-u.

 

I to je to.

 

Zadatak izgleda jednostavno, ali imaš gomilu testiranja i gomilu toga što može utjecati na točnost rezultata.

 

Nešto slično sam planirao raditi za par mjeseci, jer povremeno moram snifati podatake po raznoraznim žicama, no sada imam posla preko glave.

Poruka je uređivana zadnji put sri 1.6.2016 11:52 (Djuro von Prekoplotovich).
 
1 0 hvala 1
14 godina
neaktivan
offline
Re: Pomoć u projektu (realtime simulator)

Evo znači nečime poput ovoga bi to trebalo raditi (ovo sad ne radi nazalost).

Mozda sam ja negdje u kodu tu pogriješio pa molim savjet onda. 

 

Uglavnom, cilj bi bio da se neka while petlja vrti i u njoj se provjerava da li je proslo npr 1ms, ako jest

da se ispise rezultat koji se vec treba. Sad je pitanje da li bi to radilo uopce tako i kako to napraviti tocno?

 

try
{
Form1.Instance.playBox.Items.Clear();
TimeSpan timeLength = GetLength(Form1.Instance._recordPath + Form1.Instance.fileBox.Items[Form1.Instance.fileBox.SelectedIndex]);
int counter = 0;

if (path != null && path.Length > 0)
{
DateTime startFileTime = new DateTime();
DateTime currentFileTime = new DateTime();
DateTime currentTime = new DateTime();

double startOffset = 0;
double lastOffset = 0;
double offset = 0;

using (StreamReader reader = new StreamReader(path))
{
string[] lineArr;
startFileTime = DateTime.Parse(reader.ReadLine().Split(';')[0]);
currentTime = DateTime.Now;

/*start offset */
startOffset = (startFileTime - currentTime).TotalMilliseconds;
lastOffset = startOffset;

while (!reader.EndOfStream)
{
if (reader.ReadLine() == string.Empty) continue;
currentFileTime = DateTime.Parse(reader.ReadLine().Split(';')[0]);

while (true)
{
string line = reader.ReadLine();
if (line == null) break;

lineArr = line.Split(';');
if (lineArr.Length == 0) break;

DateTime.TryParse(lineArr[0], out currentFileTime);

///*current offset*/
offset = (currentFileTime - currentTime).TotalMilliseconds;

///*if current offset > last offset*/
if (offset > lastOffset)
{
Form1.Instance.playBox.Items.Add(lineArr[0] + " | Offset: " + lastOffset);
lastOffset = offset;
}
}
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}

Poruka je uređivana zadnji put čet 9.6.2016 12:58 (NiGHT_RiDER92).
11 godina
offline
Re: Pomoć u projektu (realtime simulator)

Sintaksa:

DateTime.TryParse ne baca exception u slučaju greške, nego vraća bool koji treba provjeriti (DateTime.Parse baca exception).
Ali to ne bi trebao bitiuzrok.

 

Da si pojednostaviš život:

 

Organizacija datoteke:

csv fromat. Najjednostavnije.

Datum i vrijeme (timestamp), pa delimiter i zatim array bytea koje si primio i koje ćeš poslati. Možeš staviti "space" između svakog pojedinog bytea.

Kod čitanja ćeš ih tretirati kao KeyValuePair<DateTime, byte[]>

 

Pseudo kod:

Otvori datoteku, čitaj liniju po liniju, parsaj string i stavljaj rezultat u Dictionary<DateTime, byte[]>.

Nakon toga postavi timer (bilo precizni (CodeProject primjer), bilo obični, koji god odabereš) na neku bezveznu malu vrijednost - tipa 15,20,30 ms.

Zablokaš trenutni thread (ManualResetEvent/AutoResetEvent i WaitOne() ili koja god metoda je danas popularna i u modi među mladima), sve dok Dictionary ne bude prazan.

Ili ne moraš blokati thread, nego prikazuj nekakav progress bar. Štogod ti štima.

 

U hendleru za timer event, prvo zaustavi timer (ako je postavljen na ponavljanje), zatim uzimaš prvi element iz Dictionary-a za slanje, oduzmeš timestamp idućeg elementa od ovog kojeg si uzeo i izračunaš Timeout.

Pošalješ podatke na port i zatim odmah setiraš timer na novu vrijednost milisekundi iz Timeouta.

To činiš sve dok ima podataka u dictionary-u.

 

To je to.

14 godina
neaktivan
offline
Pomoć u projektu (realtime simulator)

// OVAJ KOD RADI

 

public void Play(string path)
{
try
{
Thread playThread = new Thread((() =>
{

Form1.Instance.playBox.Invoke((MethodInvoker)(() =>
{ Form1.Instance.playBox.Items.Clear(); }));

Form1.Instance.fileBox.Invoke((MethodInvoker)(() =>
{
TimeSpan timeLength = GetLength(Form1.Instance._recordPath + Form1.Instance.fileBox.Items[Form1.Instance.fileBox.SelectedIndex]);
}));


if (path != null && path.Length > 0)
{
DateTime startFileTime = new DateTime();
DateTime currentFileTime = new DateTime();
DateTime currentTime = new DateTime();

using (StreamReader reader = new StreamReader(path))
{
string line = String.Empty;

line = reader.ReadLine();
string[] splitLine = line.Split(';');

startFileTime = DateTime.Parse(splitLine[0]);
currentTime = DateTime.Now;

double TotalOffset = (currentTime - startFileTime).TotalMilliseconds;
double CurrentOffset = 0;

//=============================
// Return to start of stream

reader.BaseStream.Position = 0;
reader.DiscardBufferedData();

//=============================
while (!reader.EndOfStream)
{
line = reader.ReadLine();
splitLine = line.Split(';');

if (line == string.Empty) continue;
if (line == null) break;

currentFileTime = DateTime.Parse(line.Split(';')[0]);
CurrentOffset = (DateTime.Now - currentFileTime).TotalMilliseconds;

while (TotalOffset > CurrentOffset)
{
CurrentOffset = (DateTime.Now - currentFileTime).TotalMilliseconds;
}

Form1.Instance.playBox.Invoke((MethodInvoker)(() =>
{
Form1.Instance.playBox.Items.Add(splitLine[0] + " " + "data: " + splitLine[2].ToString());
Form1.Instance.playBox.SelectedIndex = Form1.Instance.playBox.Items.Count - 1;
}));
}
}
}
}));

playThread.Start();
playThread.Priority = ThreadPriority.Highest;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}

Moj PC  
0 0 hvala 0
1
Nova poruka
E-mail:
Lozinka:
 
vrh stranice