Hallo, ich hab mir eine kleine Wetterstation (mit Extras) gebaut die soweit auch funktioniert. Angesteuert wird das ganze über die serielle Schnittstelle. Nun bräuchte ich für das RaspberryPI noch einen Dämon, der die serielle Kommunikation übernimmt. Ich müsste periodisch z.B. alle 30 Sekunden eine gewisse Zeichenkette senden. Sobald alle Messungen abgeschlossen sind (Dauer ist variabel, von 1s bis zu 10s alles möglich) werden die Daten von der Wetterstation an das RPi gesendet. Auch kann die Wetterstation von sich aus spontan Daten senden. Der Dämon müsste also alle x Sekunden eine Zeichenkette senden und immer lauschen, ob er was empfängt (und das empfangene auswerten und in einer Textdatei/MySQL-Datenbank speichern). Wie setzt ich das am besten um? Ich habe mir schon Python (die Sprache die für das RPi gepusht wird) angeschaut komme damit aber nicht wirklich klar... sieht für mich nach Spaghetti aus. In C hab ich immerhin das gefunden: http://openbook.galileocomputing.de/linux_unix_programmierung/Kap07-011.htm Ist das so ratsam? Wie würdet ihr das am besten implementieren? Ich frage mich nur wie ich das mit dem senden und empfangen sauber hinkriege (theoretisch könnte beides gleichzeitig passieren)... Viele Grüße Julian
Julian W. schrieb: > Der Dämon müsste also alle x Sekunden eine Zeichenkette senden und immer > lauschen, ob er was empfängt (und das empfangene auswerten und in einer > Textdatei/MySQL-Datenbank speichern). Wie setzt ich das am besten um? Zum Beispiel mit einem Alarm-Timer und einfachem blockierenden Lesen. Ungefähr so (Pseudocode):
1 | volatile sig_atomic_t wecker = 0; |
2 | |
3 | void handler(int sig) |
4 | {
|
5 | if (sig == SIGALRM) |
6 | wecker = 1; |
7 | }
|
8 | |
9 | ....
|
10 | |
11 | // init
|
12 | signal(SIGALRM, handler); |
13 | setitimer(ITIMER_REAL, x Sekunden); |
14 | |
15 | // Hauptschleife
|
16 | for (;;) |
17 | {
|
18 | char buf[BUFSIZE]; |
19 | int ret = read(port, buf, BUFSIZE); // blockerend lesen |
20 | if (ret < 0) // konnte nicht lesen |
21 | {
|
22 | if (errno == EAGAIN) // ein Signal! |
23 | {
|
24 | if (wecker == 1) // unser Alarm-Timer |
25 | {
|
26 | wecker = 0; |
27 | senden(); |
28 | }
|
29 | }
|
30 | else
|
31 | {
|
32 | // Lesefehler!
|
33 | }
|
34 | }
|
35 | else
|
36 | {
|
37 | verarbeite_angekommene_daten(buf, ret); |
38 | }
|
39 | }
|
Julian W. schrieb: > Ich habe mir schon Python (die Sprache die für das RPi gepusht wird) > angeschaut komme damit aber nicht wirklich klar... sieht für mich nach > Spaghetti aus. Wenn der Bauer nicht schwimmen kann, ist die Badehose schuld! Was dein C-Programm in 20 Zeilen macht macht Python in 2. Wie da Spaghettis draus werden ist mir schleierhaft. Außerdem unterstützt Python so ziemlich alle Programmierparadigmen.
Julian W. schrieb: > Der Dämon müsste also alle x Sekunden eine Zeichenkette senden und immer > lauschen, ob er was empfängt (und das empfangene auswerten und in einer > Textdatei/MySQL-Datenbank speichern). Wie setzt ich das am besten um? Wie man einen Deamon schreibt, da hast du ja schon was gefunden ;) Ich denke für den Zitierten Teil wird poll dein freund sein.
Rolf Magnus schrieb: > Zum Beispiel mit einem Alarm-Timer und einfachem blockierenden Lesen. > Ungefähr so (Pseudocode): Danke das sieht schon mal sehr gut aus :D Eine Frage hab ich noch: Erzeuge ich damit nicht eine CPU-Last von 100%? Weil die for-Schleife iwrd ja nicht "gebremst" und die CPU würde damit immer auf max. Taktfrequenz laufen oder täusche ich mich da?
Julian W. schrieb: > Erzeuge ich damit nicht eine CPU-Last von 100%? Weil die for-Schleife > iwrd ja nicht "gebremst" und die CPU würde damit immer auf max. > Taktfrequenz laufen oder täusche ich mich da? der read ist blockierend, also wird der scheduler hier denn Prozess, weg schieben bis der read Erfolg hat oder der Timeout zuschlägt. Merke jeder Systemcall ist ein "schedulling point". ausserdem wie schon gesagt, ich würde dir statt es Pseudocode der selber ein timeout bastelt denn POSIX systemcall poll ans Herz legen. ungefähr so (Achtung auch pysdocode)
1 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
|
2 | |
3 | struct pollfd pfd[] = { |
4 | { .fd = port , .events = POLLIN, } |
5 | };
|
6 | |
7 | while (1) { |
8 | ret = poll(pfd, ARRAY_SIZE(pfd), timeout); |
9 | if ( ret == 0) { |
10 | /* timeout */
|
11 | continue; |
12 | } else if ( ret < 0 ) { |
13 | fprintf( stderr "poll failes with %d=%s\n", |
14 | errno, strerror(errno)); |
15 | exit(1); |
16 | }
|
17 | |
18 | for (i= 0; i < ARRAY_SIZE(pfd); i++) { |
19 | if (!pfd[i].revents & POLLIN) { |
20 | /* no event for fd*/
|
21 | continue; |
22 | }
|
23 | ret = read(pfd[i].fd, buf, BUFSIZE); |
24 | [...]
|
25 | }
|
26 | }
|
imonbln schrieb: > ausserdem wie schon gesagt, ich würde dir statt es Pseudocode der selber > ein timeout bastelt denn POSIX systemcall poll ans Herz legen. Dabei hat man allerdings immer abhängig von der Laufzeit des restlichen Code Verzögerungen, die sich aufaddieren. Deshalb habe ich da auch den Timer genommen, nicht etwa um einen Timeout selbst zu basteln, sondern um eine präzisere Zeitsteuerung zu haben. Mag sein, daß das im konkreten Fall nix ausmacht, aber viel komplizierter ist der Code ja nun auch nicht. Übrigens empfielt es sich, bei der poll-Methode, den fd auf non-blocking umzustellen, damit read() nicht doch mal (dann eben ohne Timeout) blockiert, was laut man-Page sonst manchmal passieren kann.
Ich habe gerade gesehen, daß mein Pseudocode noch einen Fehler hat: Rolf Magnus schrieb: > if (errno == EAGAIN) // ein Signal! Das müßte eigentlich heißen:
1 | if (errno == EINTR) // ein Signal! |
EINTR bedeutet "interrupted system call", kommt also immer dann, wenn ein Systemcall wie z.B. read() durch ein Signal unterbrochen wurde.
Noch eine Frage zur seriellen Schnittstelle: wie spreche ich die serielle Schnittelle mit C unter Linux (konkret Debian) am besten an, was ist also "best practice"? Einfach /dev/tty*** öffnen? Eine Bibliothek wie die libserial benutzen? Ich muss nur ein paar Daten hin und her schieben bei 9600 Baud.
libserial ist aber C++. Einfach nur Device öffnen geht auch, vorausgesetzt die Schnittstelle ist bereits richtig konfiguriert (Baudrate, Start-,Stop- und Datenbits)
Wie sieht es eigentlich mit dem Beispiel von dieser Seite aus: http://www.tldp.org/HOWTO/Serial-Programming-HOWTO/x115.html Ist das noch Stand der Technik? Oder sollte man es besser anders machen?
Julian W. schrieb: > Wie sieht es eigentlich mit dem Beispiel von dieser Seite aus: > > http://www.tldp.org/HOWTO/Serial-Programming-HOWTO/x115.html > > Ist das noch Stand der Technik? Oder sollte man es besser anders machen? Klar ist das noch Stand der Technik. So verwende ich jedenfalls die serielle Schnittstelle immer. Frank
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.