LINUX.ORG.RU

COM порт, буфер чтения заполняется частями... Язык чистый C


0

1

Всем привет) В общем я на форуме не давно, не знаю даже как спросить, чтоб вы меня не завалили письмами типо я идиот и т.д. Так что спрошу как есть...
Пишу программу для Асинхронного считывания данных с ком порта...
Ну как пишу, написал) Всё работает, НО, не так как хочется...
Скажем устройство передаёт мне пакет из 18 байт. Моя программа принимает его кусками, сначала там 4, потом 10, потом опять 4 И каждый раз эти цыфры произвольные...
Никогда не приходит пакет целиком, для того чтобы его собрать приходится создавать второй поток и вобщем там я и завис, но я думаю что проблема где-то в конфигурации...
Вот код:

#include "putt1.h" 
/*Этой мой заголовок в нём лежит:*/
#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <pthread.h>
#include "stdint.h"
#define FALSE 0
#define TRUE 1
/*Импортируемые функии лучше не задумывайтесь зачем они, это к делу отношения не имеет*/
extern int FCS(char *rf,int len );
extern void sbor_adresov (char *bufer);
extern void Active_EP_Request_JSON (char *bufer);
extern  void Simple_desc_request_JSON (char *bufer);
extern void ZDO_IEEE_ADDR_req_JSON (char *bufer);
void signal_handler_IO (int status);   /* объявление обработчика сигнала */
volatile int STOP=FALSE;
volatile int flags;
int wait_flag=TRUE;                    /* TRUE до получения сигнала */
int res;

struct termios options,options_old;
struct sigaction saio;
char SEND[256];
char bufer [256];
unsigned char buf[256];
char *ports2[]= {
               "/dev/ttyUSB0",
               "/dev/ttyUSB1",
               "/dev/ttyUSB2",
               "/dev/ttyUSB3",
               "/dev/ttyUSB4",
               "/dev/ttyUSB5",
               } ;

#include <pthread.h>
#include <string.h>
#define FALSE 0
#define TRUE 1
int fd;
void signal_handler_IO (int status)[br]
      {
        wait_flag = FALSE;
      
      }



int open_ports(){

    fd=open(ports2[0],O_RDWR|O_NOCTTY| O_NDELAY|O_NONBLOCK);

    if (fd<0){ return 1;}
    printf("\nPort Open - 1  \n");
    int fres = tcflush(fd, TCIFLUSH);
    if (fres < 0){printf("tcflush() error %d\n", fres);}
saio.sa_handler = signal_handler_IO;
sigemptyset(&saio.sa_mask);
saio.sa_flags = saio.sa_flags|SA_SIGINFO;
saio.sa_restorer = NULL;
saio.sa_sigaction = signal_handler_IO;
sigaction(SIGIO,&saio,NULL);
fcntl(fd, F_SETOWN, getpid());
fcntl(fd, F_SETFL, FASYNC);
tcgetattr(fd,&options_old);
 options.c_cflag |= (B115200 | CS8 | CLOCAL | CREAD| CRTSCTS  );
 options.c_cflag &= ~( ICANON );
     options.c_iflag |= IGNPAR|IGNBRK;
     options.c_cflag &= ~(CS5 | CS6 | CS7 );
     options.c_cflag |= CS8;
     options.c_iflag &= ~(IXON | IXOFF | IXANY );
	 options.c_cflag &= ~(PARENB | PARODD | ECHO | ECHOE |ISIG ); 
      options.c_oflag &= ~OPOST;
      options.c_lflag = 0;
     options.c_cc[VMIN] = 0;     
      options.c_cc[VTIME] = 0;
      options.c_cflag &= ~ CSTOPB;
       options.c_cflag &= ~CSIZE;
     tcflush(fd, TCIFLUSH);
     tcsetattr(fd,TCSANOW,&options);



                                    }

void* read_only () {
  open_ports() ;

  while (STOP==FALSE) {[br] /*Это бесконечный цикл неосновного потока, раньше программа была однопоточная и было удобно, пока я не заметил, что буфер мой рассыпается на части*/[br]

    if (wait_flag==FALSE) { 
          int  ee=0;
            res = read(fd,buf,255);
           
          for (;ee<res;ee++) {
             printf("buf[%i]:%x \n",ee, buf[ee]);
             bufer[ee]=buf[ee];

                             }
           
printf ("---\n");

            wait_flag = TRUE;
            int fres = tcflush(fd, TCIFLUSH);
            if (fres < 0){printf("tcflush() error %d\n", fres);}


                                  }


                        }

        tcsetattr(fd,TCSANOW,&options_old);


                }
int reads () {
    pthread_t t1;
    pthread_create(&t1,NULL,read_only,NULL);
/*Ну это запуск неосновного потока*/
             }
int write_read (char *Send_buf,int len){ /*Запись в порт работает прекрасно*/
int e=4;
unsigned char result =0x00;
for (;e<len;e++){result ++;}
Send_buf[1] = result;
int i=0;
    int resFCS = FCS(Send_buf,len);
    for (;i<len;i++){
        SEND [i] = Send_buf [i];
                     }
        SEND [len] = resFCS;

int foll;
usleep(500);
foll = write(fd, SEND, sizeof(SEND));
usleep(500);
if (foll < 0){printf("write error %d\n", foll);}


                                        }
Вобщем я перепробовал и канонический и неканонический ввод,
кучу разных настроек из интернета и сам побредил чуток с конфигурацией А буфер как рассыпался так и рассыпается
FE 45 56 87 DD 55 AA 44 99 11 88 11 88 00 11 - должен быть такой,
а приходит
FE 45 56 87 потом
DD 55 AA 44 99 потом
11 88 11 88 00 11
Вот это я называю рассыпается)
А так как у меня это в бесконечном цикле нужен второй поток чтобы исправить, а это накладки на проц и оперативку...
А мне они не к чему)
Да и не люблю я сишные потоки)

Я, к великому моему сожалению, помочь по вопросу не могу. Но посмотри лоркод. Намного читабельнее станет.

B ()
Ответ на: комментарий от vazgen05

Опередил, чертяка! Надо меньше кофе пить.

B ()
Ответ на: комментарий от vazgen05

Щас исправлю, блин когда создавал вроде всё так аккуратно было, а тут бац и на тебе)

Titan_2014 ()
Ответ на: комментарий от Titan_2014

Уже лучше, но оберни код. Спасибо за внимание.

B ()
Ответ на: комментарий от Titan_2014

Молодец, спасибо.

Всё сделал) Прикольно у вас тут)

Оставайся, тут еще и весело!

B ()

Мне почему-то кажется, что это нормальное поведение для неблокирующего I/O. Сколько в буфер успело прийти байт, столько тебе read() сразу и возвращает.

vazgen05 ★★ ()

А буфер как рассыпался так и рассыпается
FE 45 56 87 DD 55 AA 44 99 11 88 11 88 00 11 - должен быть такой,
а приходит
FE 45 56 87 потом
DD 55 AA 44 99 потом
11 88 11 88 00 11

Язык чистый C

Ты бывший вебдизайнер штоле?

nanoolinux ★★★★ ()
Ответ на: комментарий от vazgen05

А ты кажется прав, как это исправить, может блокирующий сделать?

Titan_2014 ()

в следующий раз перед отправкой сделайте над кодом:

$ astyle --style=allman code.c

anonymous ()
Ответ на: комментарий от Titan_2014

А ты кажется прав, как это исправить, может блокирующий сделать?

А что собственно требуется то?

По последовательному порту ходят байты, а не пакеты. Если хочется выделять пакет в вашем понимании, то нужно определить и запрограммировать условия, как этот пакет выделить. Ну скажем «пауза не менее 500 мс, потом 18 байт принять» Или «18 байт, заканчивающиеся 00 11»

Ну или может для быстроты «принимать всё в течение 5 сек», потом вывести принятое.

Elyas ★★★★★ ()
Последнее исправление: Elyas (всего исправлений: 1)
Ответ на: комментарий от Elyas

Да знаю я что байты) Всё забудем про пакеты) Каждый раз мне в буфер устройство шлёт разное количество данных) Но я точно знаю что первым байтом всегда будет 0xFE а дальше неопределённое количество но не больше 256... Может быть 18 может быть 25 может да по разному кароче) Смысл в том что моя программа зашвыривает меня кусочками от этих 18... Я точно знаю что это кусочки именно этих 18... Потому что я тыкаю кнопку на одном устройстве, оно по сети передаёт пакет на устройство, подсоединённое к компу, а потом этот пакет через ком порт отправляется ко мне на комп, только кусками а не целиком... Была правильная мысль

 Мне почему-то кажется, что это нормальное поведение для неблокирующего I/O. Сколько в буфер успело прийти байт, столько тебе read() сразу и возвращает.

vazgen05 ★ (16.06.2014 15:05:09)
Только мне не хватает знаний как исправить конфиг... Ибо в инете пишут всякую ерундень для простых случаев ввода\вывода

Titan_2014 ()
Ответ на: комментарий от Elyas

Касаемо 5 секунд, мне нужно бесконечно слушать порт, поскольку устройства в сети шлют мне команды только при нажатии кнопки

Titan_2014 ()
Ответ на: комментарий от Titan_2014

так как у меня это в бесконечном цикле нужен второй поток чтобы исправить

где логика? почему в читающем потоке на пакеты не побить поток данных?

anonymous ()
Ответ на: комментарий от anonymous

вообще непонял... У меня уже данные расшибаются в этом самом потоке а мне этого не нужно ... мне нужен этот пакет целиком чтобы был в буфере, чтобы он туда весь залез и я его забрал, за один такт цикла, за один вызов функции read (); Один такт цикла, не 2 не 3 а один, чтобы можно было им воспользоваться ... Но вместо этого реад мне возвращает за один такт, только часть от этого пакета и поэтому появляется второй поток, ну как появляется я сам его создаю, который мне не нужен в моём коде, потому что это тупость... Ноуто то пофигу, а вот устройство виснуть будет по страшному...

Titan_2014 ()
Ответ на: комментарий от Titan_2014

Набросок:

do {
  nanosleep(100000);
  res=read(fd, buf,255);
} while (res == 0);
do {
  len+=res;
  nanosleep(100000);
  res=read(fd, buf+len,255-len);
} while (res != 0);


Elyas ★★★★★ ()
Ответ на: комментарий от Elyas

Это что за набросок за такой? Похоже на реализацию прослушки, только без функции signal handler io Первым циклом мы читаем буфер и пока там нифига нету мы его читаем,потом что то появилось и вторым мы уже читаем сам буфер , а что за переменная len? У меня вроде нету такой в коде) И я никогда не видел, чтобы к массиву прибавляли что-то ... Может пояснишь что это значит buf+len мне не совсем понятно)

Titan_2014 ()
Ответ на: комментарий от Titan_2014

ну пропустил я

int len=0;
я и не обещал готовую программу.

len - количество принятых байт от начала передачи после паузы. buf+len - последующие принятые байты очередной вызов read должен класть не с начала буфера, а продолжать со следующей за последним принятым ячейки.

Elyas ★★★★★ ()
Ответ на: комментарий от Titan_2014

И я никогда не видел, чтобы к массиву прибавляли что-то

buf в данном случае это не массив, а адрес первой ячейки массива.

Elyas ★★★★★ ()
Ответ на: комментарий от Elyas

Ты мозг)))) Слушай всё сработало)))) Гдеб ты ни был вагон счастья тебе )))))))))))))))))))))))

Titan_2014 ()
Ответ на: комментарий от Titan_2014

Слишком много хочешь от компорта. В общем смотрю тебе уже всё объяснили.

nanoolinux ★★★★ ()

Тебе надо либо по уже пришедшим частям понимать, сколько еще осталось, либо определить таймаут, внутри которого все приходит. Решение с нанослипом это его топорная побайтовая разновидность. Ком-порт поточный, как tcp-сокет, у него нет понятия границы пакета, всегда забираешь сколько есть и если надо ждешь еще.

зы: и на будущее прячь свои правые скобки, ты в приличном обществе. Удивляюсь, как тебя еще обратно в контакт не макнули.

arturpub ★★ ()

Ну и простынищща!

А что я в ней не вижу select или poll/epoll? Если у тебя неблокирующие операции (а судя по инициализации, они неблокирующие), то нужно select'ами какими-нибудь пользоваться.

Либо забульбенивай отдельный поток для работы с портом и в нем уже блокирующие операции.

Eddy_Em ☆☆☆☆☆ ()

Хм, ты еще и умудряешься не терять данные... Тогда в чем проблема? Посылай длину посылки первым словом — и будет тебе счастье. Потихоньку забиваешь буфер, пока нужное количество байт не примешь (ну, можно еще таймер воткнуть, чтобы отлавливать затыки).

А можно вообще завести циклический буфер и читать из него помаленьку (но, похоже, тебе такой вариант не понравится, т.к. ты хочешь сразу весь пакет принимать).

Eddy_Em ☆☆☆☆☆ ()

Придется с этим смириться, на уровне пользовательской программы так и будет.

ilovewindows ★★★★★ ()
Ответ на: комментарий от Eddy_Em

Ну потому что мне эти селекты показались безполезными... Делал я поток, эть целая морока наладить общение 2х параллельных потоков... Так как надо ... Кода получилось не мало, мне показалось, что я сделал фигню и вот собственно написал сюда на форум)

Titan_2014 ()
Ответ на: комментарий от Eddy_Em

Данные само собой я не теряю, ибо конфиг заточен чисто под устройство с которым я работаю) твой подход не корректен для моей задачи) Но спасибо за идею) Вот парень там прислал с двумя циклами, просто шик получилось)) Нанослипы я убрал само собой) Ну и ещё кое где таймоут поставил и всё Пакеты полностью приходят)

Titan_2014 ()
Ответ на: комментарий от nanoolinux

Как говориться если шпилить,то королеву, если воровать - то миллион ;D

Titan_2014 ()
Ответ на: комментарий от Titan_2014

Делал я поток, эть целая морока наладить общение 2х параллельных потоков.

Да ладно тебе! Запили в shm буфер, куда и скидывай принятые данные. О готовности извещай флагом. Но очередь на мой взгляд в данном случае была бы значительно удобней.

Eddy_Em ☆☆☆☆☆ ()
Ответ на: комментарий от Eddy_Em

Нехочу, не люблю потоки... Мне не нужна масштабная программа, я создаю наборчики из простых программок, которые буду объединять потом

Titan_2014 ()

А в чём проблема? Читай по байту -> будет приходить одинаково. Или options.c_cc[VMIN] подстраивай под требуемый размер(если ты его знаешь заранее) - должен будет ждать сколько попросишь.

DonkeyHot ★★★★★ ()
Ответ на: комментарий от DonkeyHot

Да нет уже никакой проблемы... С vmin vtime я игрался... Сейчас получилось нечто круче, чем хотелось)

Titan_2014 ()
Ответ на: комментарий от Titan_2014

Сейчас получилось нечто круче, чем хотелось

Покажи

Eddy_Em ☆☆☆☆☆ ()
Ответ на: комментарий от Eddy_Em

Ну чтобы всё показать нужно весь проект кинуть, а мине нельзя, уволят :)

Titan_2014 ()
Ответ на: комментарий от Eddy_Em

Ну да, пока небольшие... Вот доделаю, то что делаю и жизнь наладиться)

Titan_2014 ()

На удивление спокойный тред с беззлобными комментариями, не узнаю ЛОР.

mix_mix ★★★★★ ()
Ответ на: комментарий от mix_mix

Зашел проверить, сам охреневаю. Накинуть что-ли, а то набегут ведь потом со всех щелей...

arturpub ★★ ()

Эх, молодость. Почитай маны и добавь в код чего-нибудь из select/poll.

Delirium_veritas ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.