Nowe posty

xx Problem ze sterownikami. (5)
2024-04-13, 21:25:16
xx Instalacja xfce4 (2)
2024-04-13, 16:20:17
xx Serie kompilacji bez instalacji dla “emerge” w Gentoo (2)
2024-04-08, 18:40:04
xx Plasma 6 w Neonie ssie trochę mniej ... (17)
2024-04-05, 10:03:46
xx Problem z Linux Lite po instalacji (3)
2024-04-03, 14:23:40
xx Jak właczyć num locka przy starcie systemu debian 12? (12)
2024-04-02, 17:43:54
xx Brak dźwieku w systemie. (5)
2024-04-02, 16:13:41
xx Dystrybucja pod HP Omen (7)
2024-03-29, 11:33:05
xx [Poradnik] Wyszukiwanie Sterowników (2)
2024-03-27, 21:08:23
xx Ile pingwinów? (1)
2024-03-27, 08:59:24

Autor Wątek: Linux:równoległy zapis/odczyt portów szeregowych  (Przeczytany 2082 razy)

dominik90183

  • Gość
Linux:równoległy zapis/odczyt portów szeregowych
« dnia: 2015-03-04, 22:34:52 »
Witam wszystkich,

Srodowisko: Linux (arm beaglebone)
Problem: równoległy zapis/odczyt z portów szeregowych(komunikacja typu "żądanie" "odpowiedź")
Opis:
potrzebuję zrobić komunikację z 4 niezależnymi  portami szeregowymi  (/dev/ttyS0.. /dev/tty/S3) działającymi w trybie RS485(MODBUS). Komunikacja ma na celu okresowe (1s) odpytywanie czujników oraz  zapisywanie danych np w plikach. Ponieważ kommuniacja z czujnikami trawa ~0.6 s chciałbym to zerealizować w sposób równloegły. Pojawiło się kilka rozwiązań ale w jednym z nich mam problem i nie  wiem dlaczego.

Rozwiązanie (ciężko to tak nazwać ponieważ nie działa tak jak należy )polega na utworzeniu 4 procesów. Proces "rodzic" tworzy kolejno 4 "potomków", którzy to są odpowiedzilni za wysłanie poprawnego żądania o dane oraz oczekiwanie przez pewien czas na odpowiedź. Po jej otrzymaniu odpowiedzi dane są zapisywane do 4 odzielnych plików.  Generalnie z każdego czujnika (32 na kanał) powinno przyjsc 11 bajtów. Niestety dane z losowych czujniów są niepoprawne - czasem złe CRC a czasem poprosu za mało danych i  wylatuje na ograniczeniu czasowym.
Jeśli uruchomię 4 procesy "potomków " kaskadowo (wstawiając usleep(600000) wykonują się jeden po drugim ) wszystko działa jak należy.

Proszę o analizę niżej umieszczonego kodu oraz wzkazanie miejsc gdzie moga pojawic się wg Was  problemy.

#### File:PortDrive.h####
..
typedef struct
{
int PortNo;
int PortDescriptor;
}Port_t;
..
#### File:PortDrive.c####
..
Port_t Port;

Port_t * PortGetPtr()
{
    return &Port;
}

Port_Open()
{
   char Device[32];
   sprintf(&Device[0],"/dev/ttyS0%i",Port.PortNo);

   Port.PortDescriptor = open(&Device[0],O_RDWR|O_NDELAY|O_NOCTTY);
   if(Port.PortDescriptor < 0)
{
     printf("Krzak ! on pid  %d ",getpid());
}
}
Port_Close()
{
    close(Port.PortDescriptor);
}
}
..
..
#### File:main.c####

#include

#include "modules/Portdriver.h"

#include
#include
#include

void _make_processes(void);

int ThreadPID;

Port_t* pPort;

int main(int argc, char *argv[]) {


        pPort=PortGetPtr();
        MakeThreads();

        if (ThreadPID == 0)
        {
            int i=0;
                Port_Open();
                /* Wait for response and read data */
                Port_HandleResponse();
                /* Write data to file */
          };

        return 0;
}
/*make child processes */
void _make_processes(void) {

        ThreadPID = fork();
        setpriority(PRIO_PROCESS, ThreadPID, -20);

        if (ThreadPID == 0) {
                /*child 0*/

                /*Used device will be /dev/ttyS00*/
                pPort->PortNo-0;
                pPort->Gpio-PORTDRIVER_CNTRL_PIN0;
        };
        if (ThreadPID != 0) {

                ThreadPID = fork();
                setpriority(PRIO_PROCESS, getpid(), -20);

                if (ThreadPID == 0) {
                        /*child 1*/
                       // usleep(600000) <-- pomaga :-)
                        /*used device will be /dev/ttyS01*/
                        pPort->PortNo=1;
                        pPort->Gpio = PORTDRIVER_CNTRLPIN1;
                };
                if (ThreadPID != 0) {

                        ThreadPID = fork();
                        setpriority(PRIO_PROCESS, getpid(), -20);

                        if (ThreadPID == 0) {
                            /*child 2*/
                             // usleep(2*600000) <-- pomaga :-)
                            /*Used device will be /dev/ttyS02*/
                            pPort->PortNo=2;
                            pPort->Gpio = PORTDRIVER_CNTRLPIN2;
                        };
                        if (ThreadPID != 0) {

                                ThreadPID = fork();
                                setpriority(PRIO_PROCESS, getpid(), -20);

                                if (ThreadPID == 0) {
                                    /*child 3*/
                                    // usleep(3*600000) <-- pomaga :-)
                                    /*Used device will be /dev/ttyS03*/
                                    pPort->PortNo = 3;
                                    pPort->Gpio = PORTDRIVER_CNTRLPIN3;
                                };
                        };
                };
        };
}
EDIT: Dodane znaczniki [ code ]

Offline Paweł Kraszewski

  • Administrator
  • Guru
  • *****
  • Wiadomości: 3056
  • Lenistwo jest matką potrzeby = babcią wynalazku
    • Zobacz profil
Linux:równoległy zapis/odczyt portów szeregowych
« Odpowiedź #1 dnia: 2015-03-05, 14:20:55 »
Generalnie takie coś to już bardziej na wątkach niż na procesach... Masz świadomość, że ten program forkuje (robi klony całego siebie, wraz z otwartymi plikami) a nie tworzy wątki (jak wynika z nazw funkcji i zmiennych użytych w programie)? Zmiana zmiennej - nawet globalnej - w jednym procesie nie ma wpływu na tą zmienną w drugim? Inaczej niż w wątkach, gdzie zmienna globalna jest wspólna dla wszystkich wątków?

(nie do końca poprawne nazwy i użycia funkcji - bardziej chodzi o strukturę)
void* funkcja_watku(void * v){
 dev = wyciagnij_nazwe_dev(v);
 d = open(dev,...);
 while(!koniec){
  read(d,..);
  przetworz_dane();
 }
}

main() {
 t1 = thread_start(funkcja_watku,"/dev/ttyUSB0");
 t2 = thread_start(funkcja_watku,"/dev/ttyUSB1");
 // plus ile tam portów trzeba jeszcze obsłużyć
 thread_join(t1);
 thread_join(t2);
 // Plus na ile tam wątków trzeba poczekać
 return 0;
}
A najlepiej na eventach, a konkretnie na konstrukcji select(2).
(Skundlona) struktura kodu jest taka:
main() {
 fd1 = open(...)
 fd2 = open(...)
 // Otwarcie wszystkich plików w _trybie nieblokującym_

 while(!koniec) {
  FD_SET(...);
  FD_SET(...);
  // Ustawienie watchy na każdy deskryptor wejściowy
  n = select(...); // Czekanie na event
  if(n==-1) { Obsługa błędu }
  if(FD_ISSET(...)) { Opitolenie odczytu z pierwszego portu (*)}
  // Nie ma else, bo kilka ISSET mozę odpalić naraz i wszystkie trzeba obsłużyć.
  if(FD_ISSET(...)) { Opitolenie odczytu z drugiego portu }
  if(FD_ISSET(...)) { Opitolenie odczytu z trzeciego portu }
 ...
 }
 close(...)
 close(...)
 close(...)
 // Posprzątanie
 return 0;
}
(*) Jako, ze dane mogą przychodzić w kawałeczkach np. po 1 bajt, to każdy port powinien mieć bufor, do którego zbierasz jego dane, aż będą kompletne. Wtedy robisz analizę i odpowiednią reakcję i w końcu wracasz na początek bufora.
Paweł Kraszewski
~Arch/Void/Gentoo/FreeBSD/OpenBSD/Specjalizowane customy