Odczyt danych z portu szeregowego

0

Cześć
Chciałbym odczytać dane z portu COM przez PHP z terminala. Robiłem kilka prób według różnych poradników, ale mam ciągle problem z prawami dostępu.

Korzystałem z: https://www.walkswithme.net/read-serial-port-with-php
Po wpisaniu w konsoli: cat /dev/ttyS0 otrzymuje dane z urządzenia (w tym przypadku jest do waga 'gramowa')
W PHP przy funkcji fopen mam błąd: brak dostępu
Korzystam z systemu Fedora. Dodałem tak jak w tutorialu użytkownika apache do grupy dialout

Próbowałem też kilka innych tutoriali, ale ten sam efekt (wszystkie używały klasy php_serial.class.php, czasem lekko zmodyfikowanej ). Może ktoś robił coś takiego i podpowie co trzeba zrobić?

1

Jak odpalasz aplikacje? konsola? z jakiego usera? czy może przez apache/nginx/fpm, w ostateczności nadaj prawa chmod 777 /dev/ttyS0

1

Użyj gotowca: https://github.com/ppelisset/php-termios/blob/main/src/TermiosFunctions.php
Przez termios ustawisz baud rate itp.

0

Wymyśliłem to sobie tak: na tym terminalu odpala się przeglądarka w trybie kiosk i wchodzi na stronę formularzy, które sobie przygotowałem (jest to w html, takie uniwersalne, żeby można było używać na wszystkich urządzeniach), na tym terminalu chciałem tylko odpytać przez Ajax localhost, który wstawił by mi do formularza aktualny odczyt, w tym przypadku z wagi, która jest podłaczona do terminala na którym się wypełnia dane, żeby nie trzeba było przepisywać 😀 Więc to działa tak jak zwykły skrypt odpalany z przeglądarki.

1

Najlepiej żebyś zrobił poza PHP jakiś bufor, do którego na bieżąco zapisywane są dane przychodzące na port szeregowy (swoją drogą analogicznie możesz zrobić bufor wychodzący).
Innymi słowami napisz aplikację, która cały czas nasłuchuje na porcie i to co przyjdzie zapisuje do pliku a wtedy z PHP masz łatwą sprawę bo jedynie musisz odczytać ten plik.
Rozmiar bufora systemowego/sprzętowego też jest ograniczony więc jak nie będziesz zapisywał na bieżąco to nie możesz mieć pewności, że odebrałeś wszystko co przyszło.

Inna sprawa to dowiedzieć się jak ta waga podaje odczyty. Czy "pluje" danymi cały czas czy musisz ją o to zapytać.
Do samego zrobienia odczytu z poru szeregowego do bufora wystarczy skrypt napisany w bash albo prosty program w C++.

Jeśli jednak upierasz się przy PHP to można to robić bez specjalnych bibliotek:

https://www.wut.de/e-50513-00-apus-000.php

<?php

$serialDevice = '/dev/ttyS0';  // Nazwa portu szeregowego (np. COM1 w Windows lub /dev/ttyS0 w Unix/Linux)
$baudRate = 9600; // Prędkość transmisji
$timeout = 3; // Maksymalny czas oczekiwania na odpowiedź (3 sekundy)

// Otwieramy port szeregowy
$fp = fopen($serialDevice, 'r+'); // Używamy trybu 'r+' dla czytania i pisania

if (!$fp) {
    die('Nie można otworzyć portu szeregowego');
}

// Konfigurujemy ustawienia portu szeregowego
stream_set_blocking($fp, 0); // Ustawiamy port na nieblokujący
stream_set_timeout($fp, $timeout); // Ustawiamy timeout

// Konfigurujemy prędkość transmisji, parzystość, bity danych i bity stopu.
exec("stty -F $serialDevice $baudRate");

// Wysyłamy ramkę "GET_DATA"
fwrite($fp, "GET_DATA");

// Czekamy na odpowiedź
$out = '';
$start = microtime(true);

// Pętla odczytu odpowiedzi
while ((microtime(true) - $start) < $timeout) {
    $read = fread($fp, 500 - strlen($out)); // Odczytujemy dane z bufora
    if ($read === false) {
        break; // W razie błędu kończymy pętlę
    }

    $out .= $read; // Dopisujemy odczytane dane do zmiennej $out

    // Sprawdzamy czy otrzymaliśmy już 500 znaków
    if (strlen($out) >= 500) {
        break;
    }
}

// Zamykamy port szeregowy
fclose($fp);

// Wynik
echo "Otrzymana odpowiedź: " . $out;
1

Jeśli ta waga jest podłączona przez USB to bezpośrednio z przeglądarki możesz uzyskać do niej dostęp https://webserial.io/

1

napisz w C rozszerzenie do PHP

0

@4w0rX4t4X przy fopen mam błąd, dodawałem chmody na ttyS0 i użytkownika apache do grupy dialout

Warning: fopen(/dev/ttyS0): Failed to open stream: Permission denied in
   /var/www/html/get_value.php on line 7

Mógłbym zrobić bufor, ale chce wywołać odczyt w momencie przyciśnięcia przycisku na stronie.
Ustawiłem transmisję przez RS232 na urządzeniu, wyłączyłem transmisje ciągłą, aby nie pluło na okrągło i działa to teraz tak:
W jednym terminalu odpalam polecenie:

read -t5 OUTPUT < /dev/ttyS0 && echo $OUTPUT

W drugim wysyłam polecenie:

echo -e "SI" > /dev/ttyS0

i w pierwszym terminalu otrzymuje wynik.

Działa to nawet na domyślnych ustawieniach

stty sane < /dev/ttyS0

@P2420 Waga jest podłączona przez RS232 - tutaj na tej stronie w przeglądarce wyskakuje prośba o dostęp do portów, a chciałbym tego uniknąć, zrobić to w tle 😀

@Miang jeśli zrobię takie rozszerzenie to nie będzie dalej problemów z tym że apache nie ma dostępu do ttys0?

Takie najprostsze rozwiązanie to wykonać te dwa polecenia (read i echo) w php ale odbijam się od braku dostępu.. :D

1
.Al napisał(a):

@4w0rX4t4X przy fopen mam błąd, dodawałem chmody na ttyS0 i użytkownika apache do grupy dialout

Warning: fopen(/dev/ttyS0): Failed to open stream: Permission denied in
   /var/www/html/get_value.php on line 7

No ewidentnie brak uprawnień. Musisz to ogarnąć.
Możesz jeszcze zobaczyć czy wywołanie komend systemowych z poziomu PHP działa t.j.

exec ('echo -e "SI" > /dev/ttyS0');

Pewnie nie zadziała co jedynie potwierdzi, że nie ma uprawnień do portu lub jest już zablokowany przez inną aplikację.

Mógłbym zrobić bufor, ale chce wywołać odczyt w momencie przyciśnięcia przycisku na stronie.
Ustawiłem transmisję przez RS232 na urządzeniu, wyłączyłem transmisje ciągłą, aby nie pluło na okrągło i działa to teraz tak:
W jednym terminalu odpalam polecenie:

read -t5 OUTPUT < /dev/ttyS0 && echo $OUTPUT

W drugim wysyłam polecenie:

echo -e "SI" > /dev/ttyS0

No i to jest ok.

@P2420 Waga jest podłączona przez RS232 - tutaj na tej stronie w przeglądarce wyskakuje prośba o dostęp do portów, a chciałbym tego uniknąć, zrobić to w tle 😀

@Miang jeśli zrobię takie rozszerzenie to nie będzie dalej problemów z tym że apache nie ma dostępu do ttys0?
Takie najprostsze rozwiązanie to wykonać te dwa polecenia (read i echo) w php ale odbijam się od braku dostępu.. :D

Próbowałeś:

sudo chmod a+w /dev/ttyS0

albo z PHP:

$fh1 = fopen("/dev/ttyS0", "w+");
fwrite($fh1, "SI\n"); 
fread($fh1, 100);
echo $fh1;
2

@.Al Skoro to Fedora to sprawdz czy nie masz zalaczonego SELinuxa w trybie enforcing: getenforce albo sestatus
jesli zwroci "enforcing" to sprobuj przelaczyc w tryb permissive:
sudo setenforce 0
i potem odpal jeszcze raz ten skrypt w php dla sprawdzenia czy to to bylo przyczyna.

0

Cześć
Przestawienie na tryb permissive pomogło ostatecznie i już działa, taka końcowa komenda w kodzie to:

exec('echo -e "S" > /dev/ttyS0 && read -t5 OUTPUT < /dev/ttyS0 && echo $OUTPUT');

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.