Timing im Embedded Projekt



  • Hallo Leute,

    ich bin neu im Forum und hoffe, dass ihr mir helfen könnt.

    Ich bearbeite gerade ein Projekt, wo vom CAN Daten eingelesen werden, bearbeitet werden und dann als json-string via Socket weitergereicht werden soll.

    Programmiert werden soll das ganze in C++.

    Das Timing ist wie folgt:
    Aller 40ms muss ich mir Daten vom CAN holen.
    Diese werden unterschiedlich verarbeitet.
    Einiges wird aller 40ms durchlaufen und anderen Modulen zur Verfügung gestellt.
    Anderes nur aller 1s (ein Zyklus).

    Am Ende habe ich mehrere Daten, die alle nach 1s immer via Socket rausgeschickt werden sollen.

    Programmiert ist noch nix. Bis jetzt habe ich Ablaufdiagramme erstellt, um zu schauen, wer was wie oft macht 🙂

    Meine Frage ist jetzt, wie ich am geschicktesten das Timing realisiere.
    Mir kamen Shared Memory mit Semaphoren in den Sinn, weil man da P und V so einstellen könnte, dass bestimmte Daten auf andere warten, damit sie gemeinsam nach 1s geschickt werden.

    Das ist allerdings das einzige, was mir einfällt, da ich noch nie wirklich mit embedded gearbeitet habe.

    Ich hoffe, ihr könnt mir helfen ...

    Danke schonmal

    Grüße
    EmbSofti



  • Hallo EmbSofti,

    Willkommen im C++-Forum.

    EmbSofti schrieb:

    Ich bearbeite gerade ein Projekt, wo vom CAN Daten eingelesen werden, bearbeitet werden und dann als json-string via Socket weitergereicht werden soll.

    Programmiert werden soll das ganze in C++.

    Das Timing ist wie folgt:
    Aller 40ms muss ich mir Daten vom CAN holen. ...

    spontan würde ich Dir sofort die boost.asio Library empfehlen. Allerdings bedarf es einigen Aufwand bei der Einarbeitung.
    In weit das überhaupt möglich ist, hängt von Deinem Betriebssystem und Deiner Entwicklungsumgebung ab. Daher zunächst die Frage:
    kannst Du überhaupt C++11 in vollem Umfang auf Deinem System nutzen - insbesondere was <chrono> und ggf. <thread> betrifft?

    Weiter wäre zu klären, ob Du ein boost.asio auf Deinem System zum Laufen bekommst - insbesondere die Funktionalität der Timer.

    Unabhängig davon:

    EmbSofti schrieb:

    Alle 40ms muss ich mir Daten vom CAN holen.

    Bei 'holen' werde ich misstrauisch! In jedem Fall (egal ob C++11, asio oder nicht) sollte Dein System ereignisgetriggert sein. D.h. Dein Programm 'holt' sich nicht im 40ms-Takt irgendwas, sollte sollte getriggert werden, wenn ein CAN-Telegramm eintrifft.
    Das gilt auch für den 1s-Takt - auch wenn hier die Triggerung von einem Timer übernommen wird.

    - was hast Du für ein Betriebssystem?
    - hast Du volle C++11 Unterstützung?
    - welche CAN-API benutzt Du?

    Gruß
    Werner



  • Hallo Werner,

    die boost.asio hab ich mir auch schon angeschaut, scheint sehr kompliziert zu sein für mich als Anfänger.

    Ich bekomme eine firmeninterne Hardware mit einem Pengutronix Linux drauf.
    Dieses müsste C++11 unterstützen, ist mir zumindest gesagt worden.

    Die CAN-API ist ebenfalls firmenintern aufgesetzt wurden.

    Momentan habe ich noch nicht einmal eine Entwicklungsumgebung - kannst du
    eine empfehlen ?

    Die Daten werden viel öfters vom CAN zur Verfügung gestellt, als ich sie brauche. ich soll die daten zum berechnen aber nur aller 40ms und andere daten nur aller 1s abgreifen.

    ich hoffe, ich habe soweit erstmal alle fragen beantwortet und du kannst mir besser helfen.

    auf jeden fall schon mal vielen dank für die antwort.

    EmbSofti

    EDIT:
    hab mir das <chrono> und <thread> mal angeschaut.
    Scheint genau das zu sein, was ich brauche.
    Mit den threads kann ich ja sagen, der soll warten, bis der fertig ist und dann die daten senden. auch wenn ich noch ned weiß, wie ich einen JSON string via socket schicke ????!!!! 😕 😕 😕



  • D.h. Dein Programm 'holt' sich nicht im 40ms-Takt irgendwas, sollte sollte getriggert werden, wenn ein CAN-Telegramm eintrifft.

    Kommt auf die API an ...
    Meist ist die Übergabe der Daten nur Zugriff auf nen Ringbuffer, der die angekommenen Daten puffert, mit Zeitstempel versieht.
    Mit viel Glück bekommst nen Message Counter zum ErrorFrameCounter dazu ...
    Und ne Eventschnittstelle die dich ueber neue Nachrichten informiert (XL Library von vector z.b.) ist schon echt luxus 🙂

    Auf Events kommst nur selber mit Polling ...

    Bei Ihm werden die Daten wahrscheinlich nur in nen (Baum)Struktur abgelegt ...
    Trotzdem muss es irgendwas geben wo man sich aufsynchronisieren kann, Ansonsten hasst du das übliche ETechnik Problem mit den Abtastraten ^^ du muesstest also mindestens doppelt so haeufig abfragen als wie nen (bestimmtes) Telegram kommen kann. Da nen CANBus auch nicht periodisch arbeitet, kann es auch sein das Telegramme auflaufen (Je nach Implementation der Stg's), das heisst nen CAN Frame der normal aller 100ms kommt, könnte im (Über)Lastfall 500ms gar ned kommen, und dann 5 mal im 10ms Abstand ...

    Das ist allerdings das einzige, was mir einfällt, da ich noch nie wirklich mit embedded gearbeitet habe.

    Kann da auch ned viel helfen, ich war auch immer nur auf der PC (Messtechnik auf PC) Seite unterwegs.

    Hab aber viel Embedded Programmierer jammern hoeren, was alles ned geht ^^
    ABer mit C++11 bist ja schon auf der sehr komfortablen seite ...

    Dann solltest schauen was auf thread ebene geht (PThreads ? andere Thread lib ? ) und was die kann (timing verhalten). schlimmsten Fall musst auf Kernel Threads / Interrupts runter, aka dir sowas wie nen treiber schreiben der im Kernelspace arbeitet ... und dir das zeug in den Userspace mappt.
    Aber ich hoffe und denke das so tief nicht runter musst ^^

    Ciao ....



  • Hallo RHBaum,

    danke für die Nachricht.
    ich schau nochmal durch die API, was ich zur Verfügung habe.

    Also Kernel threads muss ich nicht schreiben.
    Da habe ich nachgefragt.



  • zur API:

    ich habe keine MessageCounter oder dergleichen gefunden, aber ich komme irgendwie wieder zu semaphoren zurück, bzw mutexe und Signale.

    ich hab eine Signal Klasse in der API, die signale senden kann.

    z.b. folgende funktionen:

    send signal
    broadcast signal to all waiting threads
    lock the mutex
    unlock the mutex
    wait for signal
    wait for signal with time out

    und eine Timer klasse mit

    vStart
    vStop
    bIsRunning

    und eine Thread klasse mit

    vWaitForFinished - Blocking function, as long as the thread is running.
    vSuspend - Set the thread to suspend. The current action is not broken.
    vResume - Resume the thread by a signal.
    vStop - Leave the mainloop and stop the thread. The current action is not broken.

    reicht das, um das timing erfolgreich zu gestalten ?

    ich darf leider nicht mehr Infos über die API rausgeben 😞
    ich hoffe, ihr könnt was mit anfangen ...

    ... jetzt wo man langsam weiß, was man suchen muss, findet man auch was ... 😋 😋



  • Hallo EmbSofti,

    Eine eigene Signal- und eine Thread-Klasse ist nicht nötig, Du hast ja std::condition_variable und std::thread und std::mutex & Co. Das sollte reichen.

    EmbSofti schrieb:

    ich darf leider nicht mehr Infos über die API rausgeben 😞

    brauchst Du auch nicht. Ohne Kenntnis dieser Klassen würde ich Dir aus mehreren Gründen empfehlen alles mit std::-Sachen zu programmieren. Oder gibt es 'politische' Gründen die Firmen-API her zu nehmen ;-)?

    EmbSofti schrieb:

    Momentan habe ich noch nicht einmal eine Entwicklungsumgebung - kannst du
    eine empfehlen ?

    Ich kenne mich mit Linux gar nicht aus und meine Erfahrungen in embedded sind so alt, dass ich mir dazu keine Meinung erlaube. Du wirst wohl bei Eclipse landen. Hatte ich vor Jahren mal kurz Kontakt - es ist sicher nicht das schlechteste.

    Ich würde Dir als Struktur für Deine Applikation einen Hauptthread empfehlen (kann auch der main-Thread sein), in dem Du ausschließlich an genau einer(!) Stelle auf Ereignisse wartest. Ein Ereignis ist ein eintreffendes CAN-Telegramm oder der Ablauf eines Timers oder evt. eine Benutzereingabe.

    Jede CAN-API stellt i.A. mindestens eine Funktion (ich nenne sie mal canRead) zur Verfügung, die mehr oder weniger blockierend auf ein Telegramm wartet. Lässt sich das CAN-Interface nicht direkt in die Wartestelle(s.o.) integrieren - und das ist wahrscheinlich - dann sollte in einem eigenen Helfer-Thread per canRead auf ein CAN-Telegramm gewartet werden und nach Eintreffen eines solchen, wird das Telegramm in den Hauptthread gepostet. In dem Helferthread für den CAN-Empfang könntest Du ggf. die Telegramme schon mal filtern, um den Hauptthread nicht zu überlasten. Die eigentliche Arbeit, das Zusammenfassen der Daten und der Aufbau des JSON-Strings sollte aber erst dort geschehen.
    Trifft das Timer-Event nach 1s ein, so baust Du den JSON-String endgültig fertig und schickst ihn über den Socket. Letzteres am besten mit einem asynchronen write. Die Quittung, dass der write fertig ist, sollte auch wieder über die Wartestelle beim Hauptthread eintreffen. Die Asynchronität ist geboten, um den Hauptthread nicht übermäßig zu blockieren.

    Benutzt Du boost.asio ist das relativ easy zu programmieren. 'Relativ' meine ich gegenüber einer selbst gebastelten Lösung. Das ganze setzt voraus, dass Du einigermaßen sattelfest in C++ bist.

    EmbSofti schrieb:

    Die Daten werden viel öfters vom CAN zur Verfügung gestellt, als ich sie brauche. ich soll die daten zum berechnen aber nur aller 40ms und andere daten nur aller 1s abgreifen.

    I.A. stellt eine CAN-API-Implementierung eine Queue zur Verfügung, die die empfangenen Telegramme puffert. Du wirst also nicht umhin kommen, jedes dieser Telegramme abzuholen. Aber wie oben schon erwähnt ist natürlich eine Vor-Filterung möglich. D.h. Du verwirfst die Telegramme sofort wieder, die für Dich nicht von Interesse sind. Oder die CAN-API hat die Möglichkeit die CAN-Telegramme schon vorher zu filtern - z.B. nur bestimmte Can-Ids.

    Soll Deine Socket-Schnittstelle Server oder Client sein?
    Ist im Falle des Betriebs als Servers auch mehr als ein Client denkbar?
    Was ist der Inhalt der CAN-Telegramme? Ist es Sensorik oder Monitoring oder was anderes?

    Gruß
    Werner



  • Guten Morgen,

    naja, ich hätte gestern vor Feierabend noch ein Gespräch mit dem Zuständigen, wenn es um die CAN-Angelegenheiten geht.
    Wir haben in der API mehrere Klassen, die für das, was ich machen soll, zuständig sind und auch genutzt werden sollen.

    Ich glaube gerade, dass mir damit ein wenig die Hände gebunden sind in der Programmierfreiheit.

    Ich werde also die Klassen der API nehmen müssen.
    Auch werde ich boost nicht nehmen können, weil mein Vorgesetzter meinte, dass alles, was ich brauche die API mit bringt und ich keine externe Library zusätzlich brauche.

    Momentan arbeite ich noch auf dem Firmenrechner auf Windows und nutze erstmal DevC++. das ist ganz in Ordnung. Sobald ich auf dem Embedded Linux arbeite, muss ich mir was überlegen. Muss aber sagen, dass ich bisher immer Probleme mit Eclipse hatte. Eclipse ist meiner Meinung nach eine sehr komplexe und schwierig zu verstehende IDE, aber wenn ich nicht drumrumkomme, werde ich mich der Herausforderung stellen es zu verstehen 😃 😃 😃

    Ich stelle den Client dar und soll die JSON-Strings via Socket an ein anderes System, welches eine andere Abteilung hier programmiert weiterleiten. Diese stellen den Server dar.

    Die Daten, die ich vom CAN bekomme, sind reine binär. Die muss ich auch noch irgendwie umrechnen, um mit denen rechnen zu können.
    Eine Idee ? 😋 😋 😋

    Ich werde mit zwei CAN-Schnittstellen arbeiten müssen.
    Die eine stellt die Daten zur Verfügung, die aller 40ms kommen und ich verarbeiten muss.
    Die andere stellt Daten zur Verfügung, die aller 1s abgegriffen werden sollen und einfach durchgeschleust werden und mit den berechneten daten via Socket versendet werden sollen.



  • Ich glaube gerade, dass mir damit ein wenig die Hände gebunden sind in der Programmierfreiheit.

    Ich werde also die Klassen der API nehmen müssen.

    Und wir dir dann eben nur eingeschränkt helfen können 🙂
    Also können wir eben nur allgemeine Tipps geben 🙂

    Momentan arbeite ich noch auf dem Firmenrechner auf Windows und nutze erstmal DevC++. das ist ganz in Ordnung.

    Um Gottes WIllen !!!

    February 21th 2005 : Dev-C++ 5 Beta 9.2 (4.9.9.2) released !

    Die IDE ist veraltet (oder es gibt nen neuen branch den ich ned kenn ^^)

    Tu dir selber nen gefallen, und nimm was, was zumindest C++11 kann ^^

    Auch werde ich boost nicht nehmen können, weil mein Vorgesetzter meinte, dass alles, was ich brauche die API mit bringt und ich keine externe Library zusätzlich brauche.

    Obwohl nach der Aussage wär ich mir auch ned Sicher, ob da wirklich frei entscheiden ... darfst ^^

    Falls doch, gute Kandidaten sind:

    eclipse + cdt
    netbeans mit c++
    code::blocks (kommt devcpp vielleicht am nächsten)
    QDevelop
    die sollten immer gehen

    falls Geld ausgeben kannst / willst ...
    CLion (cmake basierend)
    Visual C++ (nur auf windows, man kann tortzdem plattformunabhängig und embedded programmieren)
    IntelliJ mit C++

    Oder auf Linux
    Anjuta (fand ich mal ganz ok, aber lange nix mehr gemacht)
    Kdevelop (komm ich z.b. gar ned klar mit, ich versteh die Konzepte da ned ^^)

    am komfortablesten -> Visual Studio
    am generichsten, aka geht fast immer und überall -> eclipse

    Generell empfehl ich immer, die IDE und den Compiler als Konstante aus der Geschichte rauszunehmen, und via buildgnerator das Projekt zu managen.
    cmake, qmake jam sind da die großen Player.
    Da kannst auch unter eclipse z.b. mit dem VS compiler bauen (nur debuggen in eclipse geht ned )
    Aber das sind fortgeschrittene Themen und erstmal solltes den EInstieg ins Projekt kriegen ...

    reicht das, um das timing erfolgreich zu gestalten ?

    Generell kannst das "timing" aka den Pollthread auch selber mit c++11 mitteln schreiben.

    thread erzeugen -> std::thread
    in der thread proc:
    - schleife mit Abbruchbedingung (um den thread koordiniert zu stoppen)
    - Zeit (Performancecounter) nehmen -> std::chrono::high_resolution_clock
    - Abrage ausführen (was zu machen hasst, aka daten holen)
    - Zeit wieder nehmen ....
    - differenz bis 40ms errechnen
    - den thread die errechnete zeit schlafen legen -> std::sleep_until
    - schleife ende

    das sollte langen um "einigermassen" genau pollen zu koennen.
    genauer im userspace ist sowieso schwer möglich, wenn dein system "hängt", wirds eh ungenau, damit muss dein programm also eh klarkommen ...

    Ciao ...

    Ciao ...



  • Hallo,

    DevC++ kann C++11, das hab ich in den Settings eingestellt.

    Es ist für mich momentan das komfortableste, was ich habe.
    Auch wenn ich schon viel darüber gelesen habe, wie schlecht es sein soll ...

    Visual Studio ist zu teuer und CLion hat bei mir nicht funktioniert.

    Mit Eclipse hab ich so meine Schwierigkeiten, aber wenn ich auf dem Linux später bin, kompiliere ich von Hand mit gcc und MakeFile.

    Okay, inzwischen hab ich auch die Infos, die ich brauche, um die CAN Daten zu bekommen.

    ich werde dann mal probieren, ob es klappt und programmieren.

    Bei allgemeinen 😃 😃 Fragen werde ich nochmal auf euch zurückkommen ...

    Aber ihr habt mir dennoch gut geholfen .... Vielen Dank 👍 👍 👍

    EmbSofti 😋 😋 😋

    EDIT:
    wir haben immer so schön mit pthreads gearbeitet in C.
    die funktionieren in C++ nicht oder ???



  • Hallo EmbSofti,

    ich stimme ja im großen ganzen mit dem überein, was RHBaum so schreibt. Mit einer Ausnahme:
    DO NOT POLL!
    mag ja sein, dass es in der embedded Welt Sachen gibt, wo einem nichts anderes übrig bleibt; z.B. um auf einen Statuswechsel an einen digitalen Eingang zu warten. Und mag ja sein, dass man in der embedded Welt allein auf der CPU unterwegs ist, und es daher eh' Wurscht ist.
    meine Empfehlung bleibt: nicht pollen, solange es nur irgendwie geht. Und in einer einer Welt, in der ein 'vernünftiges' Betriebssystem zur Verfügung steht, sollte es immer irgendwie gehen. Und Linux zähle ich dazu, auch wenn ich da noch nie darauf programmiert habe.

    EmbSofti schrieb:

    Ich werde also die Klassen der API nehmen müssen.
    Auch werde ich boost nicht nehmen können, weil mein Vorgesetzter meinte, dass alles, was ich brauche die API mit bringt und ich keine externe Library zusätzlich brauche.

    OK - derartige 'Probleme' sind bekannt. So was gibt es woanders auch - bitte doch Deinen Vorgesetzten gleich mal, dass er Dir ein Beispiel zeigt, wie man mit der firmeneigenen API eine asynchronen write auf einen Socket hin bekommt. Es geht sicher - fragt sich nur wie?

    Ich hatte oben schon erwähnt, dass ich Dir unabhängig von boost oder Firmen-API eine bestimmte Struktur vorschlage.
    Zunächst wäre da eine einheitliche Wartestelle.
    boost:

    asio::io_service io_service; // (fast) fertig
    

    Firmen-API etwa so:

    class Service // auf eine Minimum reduziert
    {
    public:
        typedef std::function< void() > event_type;
        void post( const event_type& ev ); 
        void run(); // in 'run' wird auf 'Ereignisse' gewartet und diese ausgeführt, wenn sie eintreffen
    
    private:
        //## Mutex class
        //## Signal class
        std::queue< event_type > m_queue;
    };
    

    überall da, wo '##' steht, musst Du etwas aus Deiner Firmen-API einfügen.
    Skizze der Implementierung:

    void Service::run()
    {
        for(;;)
        {
            //## warte auf Signal
            // ggf. for-Schleife beenden
            bool events_present = true;
            do
            {
                //## lock Mutex (RAII!) // ich unterstelle, Du weißt, was RAII ist; siehe auch: std::lock_guard<>
                if( m_queue.empty() )
                    events_present = false;
                else
                {
                    auto ev = m_queue.front();
                    m_queue.pop();
                    //## unlock Mutex // Wichtig, da der Funktor selbst wieder ein post machen könnte!
                    ev();
                }
            }
            while( events_present );
        }
    }
    
    void Service::post( const event_type& ev )
    {
        //## lock Mutex (RAII)
        m_queue.push( ev );
        //## notify Signal
    }
    

    Weiter empfehle ich Dir, ein CAN-Telegramm in eine Klasse zu fassen - etwa so in der Form:

    class CanTelegram
    {
    public:
        CanTelegram( long canId, const char* data, unsigned len );
    
        long CanId() const;
        typedef char* iterator;
        friend iterator begin( CanTelegram& tele );
        friend iterator end( CanTelegram& tele );
    };
    

    Dann brauchst Du auch noch jemanden, der sich um alle Daten kümmert und diese sammelt und vielleicht noch die Zusammenstellung des JSON-Strings verantwortet - ich nenne ihn mal Collector:

    class Collector
    {
    public:
        Collector( ipAdresseDesServers );
        void receive1( const CanTelegram& tele ); // wird gerufen falls ein CAN-Telegramm von dem hochfrequenten Kanal einfällt
        void receive40( const CanTelegram& tele ); // wie oben, aber von dem niederfreqenten Kanal
        void onTimer(); // wird jede Sekunde gerufen
        void OnWriteDone(); // wird gerufen, sobald der write auf dem Socket durch ist
    };
    

    Hier spielt die eigentliche Musik Deiner Applikation. Da findet die gesamte Datenhaltung und der Aufbau und das Versenden der JSON-Strings statt.

    Noch eine Funktion, die ausschließlich CAN-Telegramme empfängt:

    void receive_can( CANParamter param, Service& service, std::function< void( CanTelegram ) > sink )
    {
        canOpen/Init( param );  // Bus#, Baudrate, Filter, sonstiges
        for(;;)
        {
            char data[8];
            long canId;
            unsigned len;
            auto err = canRead( &canId, data, &len );
            if( err )
                break;  // irgendeine Fehlerausausgabe
            // -- hier ggf. schon filtern
            CanTelegram tele( canId, data, len );
            service.post( [sink, tele]() { sink( tele ); } ); // alternativ: service.post( std::bind( sink, tele ) );
        }
    }
    

    'sink' ist der Funktor, der ausgeführt wird, wenn ein CAN-Telegramm einfällt.

    Und zum Schluss noch alles zusammen stecken:

    int main()
    {
        Service theService;
        Collector collector( ipServer );
        std::thread can1Thrd( [&collector, &theService]() {  //## hier die Thread-Klasse einsetzen
            receive_can( 0, theService, [&collector]( const CanTelegram& tele ) { collector.receive1( tele ); } ); 
        } );
        std::thread can2Thrd( [&collector, &theService]() { 
            receive_can( 1, theService, [&collector]( const CanTelegram& tele ) { collector.receive40( tele ); } ); 
        } );
        std::thread timerThrd( [&collector, &theService]() {
            for(;;) // ?? Beenden
            {
                //## warte 1s
                theService.post( [&collector]() { collector.onTimer(); } );
            }
        } );
        theService.run();
    
        return 0;
    }
    

    ich gehe mal davon aus, das die Firmen-Thread-Klasse Funktoren aufnehmen kann.
    Hier werden Service und Collector angelegt, zwei Threads gestartet, für die beiden CAN-Schnittstellen. Wenn beide in einem Thread abgearbeitet werden können, dann nimm nur einen. Beide Funktionen posten die CAN-Telegarmme in den Hauptthread genauer zum Collector-Objekt. Ein Timer ruft jede Sekunde 'OnTimer()'. Hier kann dann der asynchrone Write gestartet werden und mit 'WriteDone()' meldet sich dieser zurück.
    Das Beenden der Applikation habe ich mal großzügig weggelassen. Ansonsten fehlen noch die Details zur Socket-Kommunikation.
    .. im Prinzip war's das.

    EmbSofti schrieb:

    Die Daten, die ich vom CAN bekomme, sind reine binär.

    schon klar, bei 8 Byte kann man kein XML-Format erwarten 😉
    Ich hätte nur gerne gewusst, 'was' darin steht. Sind es die Werte eines Temperatursensors? oder hörst Du die Kommunikation auf dem CAN-Bus eines VWs ab?

    EmbSofti schrieb:

    Die muss ich auch noch irgendwie umrechnen, um mit denen rechnen zu können.
    Eine Idee ?

    Ja sicher - vielleicht findest Du es zu abgefahren, aber ich nehme hier tatsächlich Streams her- ein Beispiel zu einem Binärstream findest Du hier. Das ganze Gedöns mit Endian und 2- und 4-Byte Integer oder enums lesen kann man dann darin schön kapseln.

    Gruß
    Werner



  • EmbSofti schrieb:

    Visual Studio ist zu teuer

    Mach dich mal schlau über die Nutzungsbedingungen von der Visual Studio Community Edition -- für kleinere Firmen (Mitarbeiteranzahl, Jahresumsatz) ist die gratis.

    Falls du noch weitere Tips möchtest fehlen mir hier allerdings noch Antworten auf einige Fragen.
    z.B.:

    * Wie genau muss das Timing eingehalten werden?

    * Ist es wichtig die "Sampling-Frequenz" über einen grösseren Zeitraum möglichst genau zu treffen, oder ist immer nur der Abstand zwischen zwei Samples wichtig?
    Die "Sampling-Frequenz" über einen grösseren Zeitraum könnte wichtig sein wenn die Auswertung der Daten die danach erfolgt sich darauf verlässt dass N Samples auch wirklich einer bestimmten Zeitdauer entsprechen. z.B. wenn da Fourier-Transformationen oder ähnliches verwendet werden. Wenn die Daten nur mit einer bestimmten Latenz ausgewertet oder angezeigt werden sollen könnte es allerdings egal sein.

    * Wie kommst du an die Daten dran? Gibt es ne Möglichkeit die Daten über eine Callback-Funktion reinzubekommen ("OnXxxReceived"), oder musst du sie aktiv abfragen?

    * Falls aktiv abfragen: wie lange dauert so eine Abfrage inetwa? Und läuft sie synchron oder asynchron?

    (Bis hierher alles jeweils 1x pro "Daten-Typ", also 1x für die 40ms Sache und 1x für die 1s Sache.)

    * Wie viele Cores hat die Zielplattform?

    * Wie viel RAM/Rechenpower hat die Zielplattform, und was soll/muss da noch drauf laufen?

    EmbSofti schrieb:

    EDIT:
    wir haben immer so schön mit pthreads gearbeitet in C.
    die funktionieren in C++ nicht oder ???

    pthreads kannst du mit C++ genau so gut oder schlecht verwenden wie mit C.
    Ich persönlich würde aber eher die Threading-Klassen der Standard-Library verwenden. Speziell wenn Cross-Plattform entwickelt/getestet/deployed werden soll (und eine dieser Plattformen Windows ist).
    Und vom Semaphoren würde ich persönlich die Finger lassen - Mutexen und Condition-Variablen sind i.A. alles was man braucht.



  • Hallo Werner Salomon,

    danke für die Tipps. schau ich mir gleich in ruhe an 😉

    Hallo hustbaer,

    Visual Studio wird zu teuer, wir sind eine riesengroße Firma.
    Außerdem programmieren wir ausschließlich auf Linux.
    Nur für die ersten Versuchen, wo ich die Hardware noch nicht brauche, bin ich auf Win

    die Daten werden in jeweiligen Intervallen zur Verfügung gestellt.
    ich kann mir die Daten über Signals abgreifen.
    muss diese natürlich dann aussortieren, denn die meisten kommen öfter,
    als ich sie brauche

    ich habe ARM9 prozessor mit 450 MIPS
    128 MB RAM und 512 MB Flash

    Es wird kein Cross Platform genutzt.
    Es ist reines Linux und ich habe unter Linux oft mit Pthreads gearbeitet und habe gute Erfahrung wenigstens etwas Ahnung davon.

    Alles andere ist Neuland für mich und es muss bis erste Nov-woche fertig sein



  • EmbSofti schrieb:

    Alles andere ist Neuland für mich und es muss bis erste Nov-woche fertig sein

    Muss es nicht, denn sonst hätte man jemanden beauftragt, der sich mit dem Thema auskennt.



  • ich werd auch mit meinem chef sprechen müssen.

    das projekt liegt schon ne weile da und jetzt geraten die unter zeitdruck, weil es im november im fahrzeug getestet werden soll

    und ich hab es abbekommen, weil ich neu bin und mein eigentliches projekt noch ned richtig anläuft



  • Hallo Leute,

    ich habe folgendes entdeckt und find es passend, um die ms abzuwarten.

    http://codereview.stackexchange.com/questions/40915/simple-multithread-timer

    jetzt hab ich aber ein Problem.
    ich will, dass ein thread beginnt und aller 40ms das ausführt, was ich reinschreibe.

    allerdings will ich, dass er nach 1s damit aufhört.

    ich kann jetzt natürlich einen 2. timer thread machen, der aller 40ms cnt abfragt, welches ich im ersten thread immer erhöhen lasse.

    aber wie komme ich aus dem zweiten thread wieder raus ???
    der endet in einer endlosschleife 😞 😞 😞

    #include <iostream>
    #include "Timer.h"
    
    using namespace std;
    
    int cnt = 0;
    
    /* Code */
    
    void counter(){
    
    	cnt = cnt + 40;
    	cout << "Counter steht bei " << cnt << endl;
    
    }
    
    int main (void) {
    
        Timer tHello([]()
        {
        	counter();
        });
    
        tHello.setSingleShot(false);
        tHello.setInterval(Timer::Interval(40));
        tHello.start(true);		
    
        Timer tStop([&]()
        {
            if (cnt == 1000)
        	    tHello.stop();
        });
    
        tStop.setSingleShot(false);
        tStop.setInterval(Timer::Interval(40));
        tStop.start();
    
        cout << "Beide Threads wurden beendet !!" << endl;
    
        return 0;
    }
    


  • Wieso nimmst du nicht einfach std::thread und std::this_thread::sleep_for ?
    Bzw. wenn du die Möglichkeit brauchst den Thread kontrolliert zu beenden ohne auf den nächsten 40ms Tick warten zu müssen dann halt std::condition_variable_any::wait_for statt std::this_thread::sleep_for .

    EmbSofti schrieb:

    allerdings will ich, dass er nach 1s damit aufhört.

    Wieso?
    Du kannst doch das Abspeichern der 40ms Daten, das Abspeichern der 1s Daten, das Schnüren des Gesamtpakets und das Versenden alles im selben Thread machen.

    Also

    Thread-Function:
        $message = new message
    
        while not shutdown:
            wait for next 40ms tick or shutdown
            if shutdown:
                break
    
            $d40 = fetch current 40ms data
            append $d40 to $message
    
            if one second since last message was sent:
                $d1000 = fetch current 1s data
                append $d1000 to $message
                send $message
                $message = new message
    

    Wobei send $message halt alles beinhaltet was zum Senden der Nachricht erforderlich ist, also z.B. auch die JSON Formatierung.
    Falls das zu lange dauern sollte (z.B. weil das Senden der Nachricht synchron erfolgt) kannst du ja noch einen eigenen Sende-Thread machen, und die Daten aus dem Erfassungs-Thread nur an den Sende-Thread übergeben.

    Oder du machst es vom Prinzip her so wie Werner Salomon es schon vorgeschlagen hat: jedes mal wenn Daten reinkommen pflegst du diese in ein Objekt ein das die Daten für die nächste Nachricht "sammelt".

    D.h. beim Einpflegen der 40ms Daten musst du halt gucken ob du den neuesten 40ms Datenblock im "Sammler-Objekt" ("Collector" in Werners Beitrag) überschreibst (weil noch nicht genug Zeit vergangen ist) oder einen neuen Datenblock anhängst.
    Beim Einpflegen der 1s Daten im Prinzip das selbe.
    Dann kannst du jederzeit aus den Daten im Collector einen JSON Schnippel bauen und verschicken, da der Collector immer die passenden Daten bereithält.
    Und genau das machst du dann in einem Thread periodisch jede Sekunde.
    Die Zugriffe auf den Collector musst du dabei natürlich über z.B. ne Mutex synchronisieren, was aber halbwegs trivial ist.



  • hi Leute,

    ich hab inzwischen bissel programmieren können.

    die Firmen API stellt alles zur Verfügung,
    die haben da ne eigene art alles abzuholen 🙄

    wie sende ich jetzt ein JSON-string via Socket ??? 😕

    ich hab schon viel von client-server gehört und irgendwann im studium damit berührung gehabt.
    Nur gibt es hier nicht den Server im eigentlichen Sinne.

    Ich hab meine Software auf der Hardware, also mein Programm.
    Ein anderes Programm auf dieser HW will die Daten aller 1s haben,
    als JSON String, weil die alles in Java programmieren.

    für JSON hab ich folgendes aus einem anderen Thread von mir:

    https://www.c-plusplus.net/forum/p2470836#2470836

    aber wie sende ich einen socket, wenn ich keinen server habe.
    ich soll die daten als JSON-string über http an einen bestimmten port schicken und die anderen holen sich den dort ab.
    Oder stellen die anderen dadurch, dass sie auf den port hören, den server da ??? mmh .... 😕

    Ich hoffe, meine Fragen sind ned allzu dumm und ihr könnt mir helfen 😃
    Bin schließlich frisch von der HS und hab noch viel Praxis zu lernen 🙄



  • EmbSofti schrieb:

    Oder stellen die anderen dadurch, dass sie auf den port hören, den server da ??? mmh .... 😕

    Programme die nen "listening" Port haben werden oft als Server bezeichnet, ja.



  • 😃 😃 ja stimmt, die Frage war etwas .... naja 😃 😃

    dann muss ich mich einfach nochmal durch so eine Anleitung quälen und schauen, ob ich es hinbekomme. :p


Log in to reply