Apka w C++ linux porty com

0

Witam,

Problem jest następujący:
Napisałem apke w C na raspberrypi pod linuxa , zadanie apki jest dość proste pobiera dane z jednego portu i przesyła na drugi ( w założeniu ma modyfikować te dane ) coś w rodzaju monitora/sniff`era apka działa w jedną stronę super ( pobranie i przesłanie dalej ) ale kiedy dochodzi do komunikacji 2 stronnej wszystko się sypie.

Domyślam się że problem jest w sterowaniu transmisja ewentualnie w buforze.
Wiem że wina leży gdzieś po mojej stronie , za pomoc z góry dziękuje.
Poniżej kod apki

#include <errno.h>
#include <termios.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>


int
set_interface_attribs (int fd, int speed, int parity)
{
        struct termios tty;
        memset (&tty, 0, sizeof tty);
        if (tcgetattr (fd, &tty) != 0)
        {
                //error_message ("error %d from tcgetattr", errno);
                return -1;
        }

        cfsetospeed (&tty, speed);
        cfsetispeed (&tty, speed);

        tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;     // 8-bit chars
        // disable IGNBRK for mismatched speed tests; otherwise receive break
        // as \000 chars
        tty.c_iflag &= ~IGNBRK;         // disable break processing
        tty.c_lflag = 0;                // no signaling chars, no echo,
                                        // no canonical processing
        tty.c_oflag = 0;                // no remapping, no delays
        tty.c_cc[VMIN]  = 0;            // read doesn't block
        tty.c_cc[VTIME] = 5;            // 0.5 seconds read timeout

        tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl

        tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
                                        // enable reading
        tty.c_cflag &= ~(PARENB | PARODD);      // shut off parity
        tty.c_cflag |= parity;
        tty.c_cflag &= ~CSTOPB;
        tty.c_cflag &= ~CRTSCTS;

        if (tcsetattr (fd, TCSANOW, &tty) != 0)
        {
               printf("attribut settings failed\n");
                return -1;
        }
        return 0;
}

void
set_blocking (int fd, int should_block)
{
        struct termios tty;
        memset (&tty, 0, sizeof tty);
        if (tcgetattr (fd, &tty) != 0)
        {
               printf("attr settings failed - set blocking\n");
                return;
        }

        tty.c_cc[VMIN]  = should_block ? 1 : 0;
        tty.c_cc[VTIME] = 5;            // 0.5 seconds read timeout

        if (tcsetattr (fd, TCSANOW, &tty) != 0)
                printf("atribute settings failed-set blocking\n");
}


int main(int argc, char** argv) {
	
char *portname = "/dev/ttyUSB0";
char *portoutn = "/dev/ttyUSB1";

int fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0)
{
       printf("opening in port failed \n");
        return;
}
int fdo = open (portoutn, O_RDWR | O_NOCTTY | O_SYNC);
if (fdo < 0)
{
       printf("opening out port failed \n");
        return;
}
set_interface_attribs (fd, B115200, 0);  // set speed to 115,200 bps, 8n1 (no parity)
set_blocking (fd, 0);                // set no blocking
set_interface_attribs (fdo, B115200, 0);  // set speed to 115,200 bps, 8n1 (no parity)
set_blocking (fdo, 0);                // set no blocking




                                    
char buf [2];
do{
int n = read (fd, buf, sizeof buf);  // read up to 100 characters if ready to read

// processing colected data from one end to beeing resend , allsow loging data
printf("%s",buf);
write (fdo, buf, sizeof(buf)); 

// second way 
n = read (fdo, buf, sizeof buf);
printf("%s",buf);
write (fd, buf, sizeof(buf)); 
// maybe we need usleep here , but i am guessing that colecting data to the buffer take the same time as sending so we should not have any problem 

}while(1);

	return 0;
}
1

Apka w C++

Napisałem apke w C

???

pobiera dane z jednego portu i przesyła na drugi

Domyślam się z kodu że nie chodzi o port wbudowany w RPi, tylko o jakąś przejściówkę na USB. To istotny szczegół, którego nie raczyłeś napisać.

ale kiedy dochodzi do komunikacji 2 stronnej wszystko się sypie

Ale co jest po drugiej stronie? Po której drugiej stronie? I na czym ma polegać dwustronna komunikacja, skoro „zadanie apki jest dość proste pobiera dane z jednego portu i przesyła na drugi”?

0

Nie bądź Pan takim formalistom ( oryginalnie planowałem w C++ ale w C poszło szybciej , z tond moja pomyłka :) zauważyłem po fakcie ).

Owszem ale chciałem żeby przesyłała w obie strony , po prostu żeby z perspektywy każdego urządzenia podłączonego pod port com urządzenie nie było widoczne. Ma sobie działać i tyle , oryginalnie miało działać jedno stronie ale drukarka którą podpinam wymaga pełnej komunikacji z kompem ( kiedy oryginalnie nie powinna według specyfikacji ).

Całość finalnie ma służyć jako konfigurowalne urządzenia pozwalające sprzętowo dodrukować informacje do paragonu ( kod QR/materiały reklamowe ) w taki sposób żeby nie ingerować w oryginalne oprogramowanie.

0
int n = read (fd, buf, sizeof buf);  // read up to 100 characters if ready to read
 
// processing colected data from one end to beeing resend , allsow loging data
printf("%s",buf);
write (fdo, buf, sizeof(buf));

Co zapisujesz, jeśli na read jest timeout?

0

Stawiam, że błędem jest sizeof(buf) zamiast n we write, bo zapisujesz pozostałe w buforze śmieci. BTW, jak robisz printf("%s",buf); to skąd wiesz, że na końcu siedzi \0?

Na przyszłość: nie masz chyba świadomości, że read blokuje. c_cc[VMIN] to faktycznie minimalna ilość danych jakie można przeczytać, ale c_cc[VTIME] to timeout. To co masz teraz to "jeżeli upłynie timeout zwróć zero".
Więcej tutaj: http://stackoverflow.com/questions/25996171/linux-blocking-vs-non-blocking-serial-read
i tutaj: http://linux.die.net/man/3/tcsetattr

Jeżeli potrzebujesz obsługiwać większą ilość deskryptorów naraz to polecam fcntl z O_NONBLOCK, ew. ioctl i FIONBIO dla nieblokowania select bądź poll dla obsługi IO. Aczkolwiek nie wydaje się to fundamentalnym problemem tutaj.

0

Jeżeli masz możliwość, użyj biblioteki boost, Wszystkie problemy powinny zniknąć.

0

Boost jest akurat fajnym pomysłem tutaj.
Pytanie z innej beczki ( nie ukrywam że wcześniej z rs232 pracowałem bardzo nisko poziomowo ) jak wygląda z poziomu systemu transmisja xon/xoff ( drukarka takiej wymaga ) czy znaki VSTART i VSTOP musze sprawdzać sam czy to już biblioteka obsługuje ( tzn. nigdy nie odczytam tych znaków z portu tylko system sobie gdzieś ustawia jakąś flagę że rozpoczęto/zakończono transmisje )?

2
int CopySomeDataBetweenFd(int fd1, int fd2)
    const int bufSize = 0x100; // rozmiar powinien być rozsądny a nie 2 bajty
    char buf [bufSize+1]; // zapas na zero kończące
    int readCount = read (fd1, buf, bufSize);
    if (readCount>0) {
       buf[readCount] = 0; // potrzebne ci zero kończące by nie drukować śmieci!
       printf("%s", buf); // bo inaczej tu nie wiadomo co się wydrukuje
       int writeCount = write (fd2, buf, readCount); // skopiuj tylko tyle ile wczytano
       if (writeCount < 0) {
            fprintf(stderr, "Blad zapisu danych");
            return 2;
       } else if (writeCount != readCount) {
            fprintf(stderr, "Nie zapisło się wszystko, brakuje: %s", buf+writeCount);
            return 3;
       }
    } else if (readCount < 0 ) {
       fprintf(stderr, "Blad odczytu danych");
       return 1;
    }
    return 0;
}
while(1) {
     CopySomeDataBetweenFd(fd, fdo);
     CopySomeDataBetweenFd(fdo, fd);
}
0

Dziękuję wszystkim za pomoc okazuje się że pierwsza wersja aplikacji którą pisałem ( nie ta zamieszczona tutaj tylko pełna wersja działająca w jedną stronę ) jest prawdopodobnie poprawna.

Ostatni kawałek kodu zamieszczony przez MarekR22 pozwalający na przesyłanie w obie strony powinien działać a okazało się że drukarka drukuje bzdury same , szukając błędu i nie mogąc go znaleźć napisałem krótki programik w python który korzystając z protokołu drukarki miał wydrukować jedynie hello world , odpaliłem poprzez Rasp i drukowało śmieci , odpaliłem bezpośrednio z PC(bez mojego sprzętowego monitora ) i wydruk był poprawny więc przeniosłem aplikacje na Rasp i odpaliłem z niego no i znowu śmieci :).

Zakładam w tej chwili że problemem jest po prostu przejściówka(kontroler w sumie ) USB/RS232, najprawdopodobniej na wyjściu RS podaje za niskie napięcia z tond te śmieci.
Jak ktoś ma inny pomysł to również będę wdzięczny.

Dodam jeszcze że testowałem na wszelkich ustawieniach i prędkościach , rezultat był taki sam za każdym razem jeśli drukowałem z Rasp.

Drukarka jednak działa w jedną stronę tak jak zakładałem na początku ;)

Jeszcze w ramach ścisłości dodam że przesyłałem dla testów dane z Rasp na konsole PC korzystając z tej przejściówki i dostałem śmieci na konsoli. Podejrzewam ( tak jak pisałem wyżej ) że problem jest z napięciami bo paradoksalnie jeśli podepnę tą samą przejściówkę do PC i prześle dane na drugi PC to dostaje poprawne informacje. Możliwe że Rasp ma za mało mocy na swoich USB albo co właśnie przyszło mi do głowy sterownik dla tej przejściówki od strony Rasp jest zwalony ( co było by całkiem logiczne biorą pod uwagę sposób działania ).

0

A masz na raspi echo po zawarciu rx z tx? Co to za przejsciówka i jak ją dokładnie podłączasz?

0

Możliwe że Rasp ma za mało mocy na swoich USB

To zależy od zasilacza. Jak podłączyłeś RPi słabą ładowarką do telefonu to problemy z USB masz gwarantowane.
Może pomoże hub aktywny USB (z własnym zasilaniem).

Napięcie na RS232 można też próbować podbić do nominalnych +15/-15 V za pomocą chipa MAX232, ale to już zabawa lutownicą.

0

Zasilacz ma niby 1.8A ale z wyglądu już czuje że pewnie max 800mA :/ ( takie cudo podobne do ładowarki od telefonu ).
Na echo jest ok po stronie PC ( znowu ) na Rasp bzdury...
Postaram się załatwić jakiegoś Hub-a aktywnego i wtedy będę miał pewność.

Przejściówka to jakiś g***ny no-name , nie mogę znaleźć kto jest tego producentem :/. ( nie ja kupowałem i tłumaczyłem że musi być to coś normalnego , facet się uparł że takie bo mu na PC działa , drukarka oryginalnie podpięta do POS-a była właśnie identyczną przejściówką ).

0

A co o tej przejsciowce mowi dmesg?

1 użytkowników online, w tym zalogowanych: 0, gości: 1