LINUX.ORG.RU

Прием с последовательного порта

 ,


1

1
void open_port(void){
	int fd;
	if ((fd = open(DEVICE, O_RDWR | O_NOCTTY | O_NDELAY)) == -1){
		perror("Unable to open port");
	} else {
		int n = write(fd, "Humpty Dumpty sat on a wall\r", 28);
		if (n < 0){
			fputs("write() of 28 bytes failed!\n", stderr);
		}
	}
	close(fd);
}

Как самый простой пример передачи без настроек всяких работает превосходно, а вот со чтением также просто не выходит - примеры в сети кишат «goto»[да и while(1), наверное - не совсем правильно?], а Serial Programming Guide for POSIX Operating Systems даже примеров с read() не содержит (вольные переводы оного содержат не только read(), но и кучу запутывающей информации).

Потому, ежели кто знает как минимумом строчек забрать данные с com-порта, буду признателен за слив информации. Спасибо

★★★★★

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

Обычным read в бесконечном цикле, в отдельном потоке, настраивать порт обязательно.

удваиваю.
А вообще есть 2 подхода:
1. отдельный поток, блокировка на чтении, сохранение в буфер для дальнейшей обработки. Правильно, кошерно, удобно.
2. для неосиляторов потоков, можно сбацать неблокирующее чтение и в цикле вычитывать дескриптор.

Обратить внимание на тонкости приемо-передачи сырых данных - драйвер очень любит 0x0d менять на 0x0a 0x0d.

Отлично все разжевано тут: http://www.opennet.ru/docs/RUS/serial_guide/index.html

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

библиотека и для lin и для вынь.

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

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

не горячись, там для новичка много понятней, чем в твоем примере, хотя чтение и не работает у меня. Это как учиться писать с goto, чтобы понять, чем он плох.

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

1. отдельный поток, блокировка на чтении, сохранение в буфер для дальнейшей обработки. Правильно, кошерно, удобно.

это для тех, кто не осилил poll, да?

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

Отстань со своим poll. Сто лет назад осилил потоки, они меня не напрягают и нужны по задаче.

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

щас тут нам объяснят чем poll отличается от select-a.

это для тех, кто не осилил poll, да?

Я смотрю вы из тех дивных любителей пихать в каждое примитивное приложение все умные слова, которые видели или слышали?

Можно конечно и полить. Придумать, хитрый главный цикель, систему таймаутов. Обработку всевозможных событий. ТС судя по всем не так искушен во всех этих делах, пусть для начала освоит ручной привод.

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

какой воинственный анонимный тролль. я ж говорю читать не умеешь даже по-русски - смотреть надо инициализацию порта, а не юзать как есть.

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

смотреть надо инициализацию порта

Дурачек - примеры этого надо смотреть в источниках заслуживающих доверия - man termios и тот же Serial Programming Guide for POSIX Operating Systems.

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

Анонимоус знаешь почему ты неудачник? как только поймёшь, так сразу у тебя в жизни наладится и ты станешь хоть немного адекватен.
есть вопрос, на него есть ответ, а твоё пузыряние соплями это не ответ. посмотри свой гвард, напиши пример, проверь его, запости сюда, как ответ вопрошающего, а до тех пор ты злой убогий неудачник, который кидает пустой понт по несуразному поводу.

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

Можете и дальше грызть друг друга, тема решена, но твой код по ссылке не запустился в режим приема, как и написанный по гайду в теме треда(вполне вероятно я где-то флаги не дописал/перепутал). Так что 1:1, закрываем ринг

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

Анонимоус знаешь почему ты неудачник?

Знаю, знаю - потому что ты удачник :)

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

чего-то не то делаешь - выдирал код из данной библиотеки, правда давно - всё работало.
и на будущее это не мой код.

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

Не суть важно, я часто слова перемешиваю - следует читать «код по твоей ссылке». Скопипастил, в cutecom отправил 'hello\r', которое в него же вернулось(Rx-Tx закорочены), а цикл молчит. Но пока это и не важно, поступившей информации пока более чем достаточно

minakov ★★★★★
() автор топика

Так это делается у белых людей

 import qualified Data.ByteString.Char8 as B
 import System.Hardware.Serialport
 let port = "/dev/ttyUSB0"
 s <- openSerial port defaultSerialSettings { commSpeed = CS2400 }
 send s $ B.pack "AT\r"
 recv s 10 >>= print
 closeSerial s
anonymous
()

У меня есть уже давно написанный serial <-> tcp мост, многопользовательский. Если надо могу положить куда нибудь на bitbucket.

amaora ★★
()

Рабочий код из старого проекта на Ада:

with Text_IO,
	Ada.Strings,
	Ada.Strings.Fixed;

use Text_IO,
	Ada.Strings,
	Ada.Strings.Fixed;

package body ZC.RS232 is

   package IO renames POSIX.IO;
   use Terminal;

   function Open (Port_Number : in Natural) return Descriptor is
      function Get_Port_Name (Port_Number : in Natural) return POSIX.Pathname is
         pn : constant String := Trim (Natural'Image (Port_Number), Both);
         name : constant String := Port_Name_Template & pn;
      begin 
         return To_Posix_String (name);
      end Get_Port_Name;
      Port_Name : constant Pathname := Get_Port_Name (Port_Number);
      fd : Descriptor;
      flags : Terminal_Characteristics;
	  modes : Terminal_Modes_Set;
   begin
      fd := IO.Open (Port_Name, IO.Read_Write); -- , Options => IO.Exclusive);
      Put_Line (To_String (Port_Name) & " : " & Descriptor'Image (fd));
	  flags := Get_Terminal_Characteristics (fd); -- Получить текщие флаги
	  -- иначе - мусор в полях и некорректная инициализация
	  --
	  -- Вырубаем software handshake (IXON/IXOFF)
	  modes := Terminal_Modes_Of (flags);
	  modes (Enable_Start_Stop_Input) := false;
	  modes (Enable_Start_Stop_Output) := false;
	  --
	  modes (Enable_Parity_Check) := false;
	  modes (Interrupt_On_Break) := false;
	  modes (Ignore_Modem_Status) := true;
	  modes (Canonical_Input) := false;
	  modes (Parity_Enable) := false;
	  modes (No_Flush) := false;
	  Define_Terminal_Modes (flags, modes);
	  --
      Define_Bits_Per_Character (flags, 8);
      Define_Input_Baud_Rate (flags, B9600);
      Define_Output_Baud_Rate (flags, B9600);
	  -- Без этого может читаться некорректное количество байт 
	  Define_Minimum_Input_Count (flags, Packet_Size); 
	  Define_Input_Time (flags, 1.0);
	  --
      Set_Terminal_Characteristics (fd, flags);
      return fd;
   end Open;

   procedure Close (fd : in Descriptor) is
   begin
      IO.Close (fd);
   end Close;
   
   function Read (fd : in Descriptor) return Communication_Packet is
      buffer : IO_Buffer;
	  last: POSIX.IO_Count;
	  pckt : Communication_Packet;
   begin
	  Put_Line ("Start reading...");
      IO.Read (fd, buffer, last);
	  Put_Line ("Readed: " & Integer'Image (Integer (last)));
	  if Integer (last) /= buffer'Last then
		  raise Read_Error with "RS232 read error";
	  end if;
	  pckt := Get_Packet (buffer);
	  --if not Is_Valid (pckt) then
	--	  raise Invalid_Read with "packet invalid";
	 -- end if;
	  Put_Line ("Readed #" & POSIX.IO_Count'Image (last));
      return pckt;
   end Read;
   
   procedure Write (fd : in Descriptor; pckt : in Communication_Packet) is
      buffer : IO_Buffer := Get_IO_Buffer (pckt);
      last : POSIX.IO_Count := POSIX.IO_Count (buffer'Last);
   begin
      IO.Write (fd, buffer, last);
      if Integer (last) /= buffer'Last then 
   	 	raise Write_Error with "RS232 write interrupted";
   	 end if;
	 Put_Line ("Writed ");
   end Write;

end ZC.RS232;
Darkman ★★★
()
Ответ на: комментарий от Darkman

Пример корректной инициализации на Си:

#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <errno.h>
#include <string.h>

#define BAUDRATE B38400
#define MODEMDEVICE "/dev/ttyS0"
#define _POSIX_SOURCE 1         //POSIX compliant source
#define FALSE 0
#define TRUE 1

volatile int STOP=FALSE;

int wait_flag=TRUE;                     //TRUE while no signal received
char devicename[80];
long Baud_Rate = 38400;         // default Baud Rate (110 through 38400)
long BAUD;                      // derived baud rate from command line
long DATABITS;
long STOPBITS;
long PARITYON;
long PARITY;
int Data_Bits = 8;              // Number of data bits
int Stop_Bits = 1;              // Number of stop bits
int Parity = 0;                 // Parity as follows:
                  // 00 = NONE, 01 = Odd, 02 = Even, 03 = Mark, 04 = Space
int Format = 4;
int status;

int set_rs_param()
{

   int fd, tty, c, res, i, error;
   char In1, Key;
   struct termios oldtio, newtio;       //place for old and new port settings for serial port
   struct termios oldkey, newkey;       //place tor old and new port settings for keyboard teletype
   struct sigaction saio;               //definition of signal action
   char buf[255];                       //buffer for where data is put
   

   error=0;
      strcpy(devicename,"/dev/ttyS0");
      Baud_Rate=9600;
      Data_Bits=8;
      Stop_Bits=0;
      Parity=0;
    /*  tty = open("/dev/tty", O_RDWR | O_NOCTTY | O_NONBLOCK); //set the user console port up
      tcgetattr(tty,&oldkey); // save current port settings   //so commands are interpreted right for this program
      // set new port settings for non-canonical input processing  //must be NOCTTY
      newkey.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
      newkey.c_iflag = IGNPAR;
      newkey.c_oflag = 0;
      newkey.c_lflag = 0;       //ICANON;
      newkey.c_cc[VMIN]=1;
      newkey.c_cc[VTIME]=0;
      tcflush(tty, TCIFLUSH);
      tcsetattr(tty,TCSANOW,&newkey);*/

      switch (Baud_Rate)
      {
         case 38400:
         default:
            BAUD = B38400;
            break;
         case 19200:
            BAUD  = B19200;
            break;
         case 9600:
            BAUD  = B9600;
            break;
         case 4800:
            BAUD  = B4800;
            break;
         case 2400:
            BAUD  = B2400;
            break;
         case 1800:
            BAUD  = B1800;
            break;
         case 1200:
            BAUD  = B1200;
            break;
         case 600:
            BAUD  = B600;
            break;
         case 300:
            BAUD  = B300;
            break;
         case 200:
            BAUD  = B200;
            break;
         case 150:
            BAUD  = B150;
            break;
         case 134:
            BAUD  = B134;
            break;
         case 110:
            BAUD  = B110;
            break;
         case 75:
            BAUD  = B75;
            break;
         case 50:
            BAUD  = B50;
            break;
      }  //end of switch baud_rate
      switch (Data_Bits)
      {
         case 8:
         default:
            DATABITS = CS8;
            break;
         case 7:
            DATABITS = CS7;
            break;
         case 6:
            DATABITS = CS6;
            break;
         case 5:
            DATABITS = CS5;
            break;
      }  //end of switch data_bits
      switch (Stop_Bits)
      {
         case 1:
         default:
            STOPBITS = 0;
            break;
         case 2:
            STOPBITS = CSTOPB;
            break;
      }  //end of switch stop bits
      switch (Parity)
      {
         case 0:
         default:                       //none
            PARITYON = 0;
            PARITY = 0;
            break;
         case 1:                        //odd
            PARITYON = PARENB;
            PARITY = PARODD;
            break;
         case 2:                        //even
            PARITYON = PARENB;
            PARITY = 0;
            break;
      }  //end of switch parity
       
      //open the device(com port) to be non-blocking (read will return immediately)
      //fd = open(devicename, O_RDWR | O_NOCTTY | O_NONBLOCK);
      fd = open(devicename, O_RDWR | O_NOCTTY);
      if (fd < 0)
      {
         perror(devicename);
         exit(-1);
      }


      // allow the process to receive SIGIO
      fcntl(fd, F_SETOWN, getpid());
      // Make the file descriptor asynchronous (the manual page says only
      // O_APPEND and O_NONBLOCK, will work with F_SETFL...)
      // fcntl(fd, F_SETFL, FASYNC);

      tcgetattr(fd,&oldtio); // save current port settings 
      // set new port settings for canonical input processing 
      //newtio.c_cflag = BAUD | CRTSCTS | DATABITS | STOPBITS | PARITYON | PARITY | CLOCAL | CREAD;
      newtio.c_cflag = BAUD | DATABITS | STOPBITS | PARITYON | PARITY | CLOCAL | CREAD;
      newtio.c_iflag = IGNPAR;
      newtio.c_oflag = 0;
      newtio.c_lflag = 0;       //ICANON;
      newtio.c_cc[VMIN]=13;
      newtio.c_cc[VTIME]=1;
      tcflush(fd, TCIFLUSH);
      tcsetattr(fd,TCSANOW,&newtio);

	  return fd;

}  //end of main

Darkman ★★★
()
18 июля 2013 г.
Ответ на: комментарий от yax123

yax123,
«Обратить внимание на тонкости приемо-передачи сырых данных - драйвер очень любит 0x0d менять на 0x0a 0x0d.»
А можно поподробнее?
И вообще, как с Вами на связь выйти можно? ))

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

И вообще, как с Вами на связь выйти можно

Еще бы написали «вступить в связь».
Есть мыло на яндексе с моим логином здесь. Пишите письма.

yax123 ★★★★★
()

То, что ты ищешь, называется socat. А читать/писать в его сокеты уже обычными open/read/write

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