Установка скорости передачи / dev / ttyS0 на ›115200

Я пытаюсь установить скорость передачи последовательного порта (/ dev / ttyS0) на 1 МБ (1000000). Я пробовал писать код, используя cfsset {i | o} speed () + tc {g | s} etattr (). Все, что> 115200, игнорируется.

#include <termio.h>
#include <fcntl.h>
#include <err.h>
#include <linux/serial.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

static int rate_to_constant(int baudrate) 
{
#define B(x) case x: return B##x
  switch(baudrate) {
    B(50);     B(75);     B(110);    B(134);    B(150);
    B(200);    B(300);    B(600);    B(1200);   B(1800);
    B(2400);   B(4800);   B(9600);   B(19200);  B(38400);
    B(57600);  B(115200); B(230400); B(460800); B(500000); 
    B(576000); B(921600); B(1000000);B(1152000);B(1500000);

  default: return 0;
  }
#undef B
}    

/* Open serial port in raw mode, with custom baudrate if necessary */
int serial_open(const char *device, int rate)
{
  struct termios options;
  struct termios options1;
  struct serial_struct serial;
  int fd;
  int speed = 0;

  /* Open and configure serial port */
  if ((fd = open(device, O_RDWR | O_NOCTTY)) == -1)
    return -1;

  speed = rate_to_constant(rate);
  warnx("speed: %d", speed);

  fcntl(fd, F_SETFL, 0);

  if (speed == 0)
    {
      warnx("speed == 0");

      /* Custom divisor */
      memset(&serial, 0, sizeof(struct serial_struct));

      serial.reserved_char[0] = 0;

      if (ioctl(fd, TIOCGSERIAL, &serial) < 0) return -1;

      warnx("serial.baud_base: %d", serial.baud_base);

            serial.flags &= 
      serial.flags &= ~ASYNC_SPD_MASK;
      serial.flags |= ASYNC_SPD_CUST;

      serial.custom_divisor = (serial.baud_base + (rate / 2)) / rate;

      warnx("serial.custom_divisor: %d", serial.custom_divisor);

      if (serial.custom_divisor < 1)
    serial.custom_divisor = 1;

      if (ioctl(fd, TIOCSSERIAL, &serial) < 0)
    return -1;

      if (ioctl(fd, TIOCGSERIAL, &serial) < 0)
    return -1;

      if (serial.custom_divisor * rate != serial.baud_base)
        {
          warnx("actual baudrate is %d / %d = %f",
                serial.baud_base, serial.custom_divisor,
                (float)(serial.baud_base) / serial.custom_divisor);
        }
    }

  memset(&options, 0, sizeof(struct termios));
  tcgetattr(fd, &options);
  cfmakeraw(&options);

  cfsetispeed(&options, speed ?: B38400);
  cfsetospeed(&options, speed ?: B38400);

  options.c_cflag |= (CLOCAL | CREAD);
  options.c_cflag &= ~CRTSCTS;

  if (tcsetattr(fd, TCSANOW, &options) != 0)
    return -1;

  memset(&options1, 0, sizeof(struct termios));
  tcgetattr(fd, &options1);
  warn("options1.speeds: %d and %d", cfgetispeed(&options1), cfgetospeed(&options1));

  return fd;
}

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

  //fd = serial_open("/dev/ttyS0", 115200);
  fd = serial_open("/dev/ttyS0", 460800);

  warnx("END");

  close(fd);
}

Это основано на: Как установить скорость передачи 307200 в Linux. ?

Я пробовал использовать stty и setserial в командной строке ... те же результаты.

stty -F /dev/ttyS0 1000000

1) Нужно ли мне менять код ядра (serial_core.c или 2850.c или 2850_pci.c и т. Д.)?

2) Подойдет ли код пользовательского пространства?

Эльжбета


person jski    schedule 07.01.2016    source источник
comment
Вы проверили в первую очередь, что ваш последовательный порт может поддерживать эту скорость?   -  person Alexandre Lavoie    schedule 08.01.2016


Ответы (1)


Если битрейт, который вы хотите установить, определен в <asm/termbits.h> (как указано в <termios.h>), то это торт, и нет необходимости проходить через все эти настраиваемые мешанины делителей (которые в любом случае зависят от устройства):

struct termios ttycfg;
int            fd;

fd = open ("/dev/ttyS0", O_RDWR | O_NOCTTY);
tcgetattr (fd, &ttycfg);
cfsetspeed (&ttycfg, B961200);
tcsetattr (fd, TCSANOW, &ttycfg);

Обратите внимание, что tcsetattr() вернет результат успешно, если какое-либо из запрошенных изменений может быть выполнено, поэтому, если вы изменяете несколько параметров, вам следует выполнить еще один tcgetattr(), чтобы увидеть, какие из них были успешно применены.


Кроме того: во многих системах на основе Debian по умолчанию установлен пакет под названием modemmanager, который предназначен для обнаружения и управления модемами, открывая каждый последовательный порт, который он может найти, выкрикивая AT-команды по проводам и проверяя ответы (адаптеры JTAG просто люблю, что с ними сделали это: - /). Если вы имеете дело с последовательными портами с возможностью горячего подключения (например, с последовательными USB-адаптерами), эта штука испортит вам день, поэтому вы захотите настроить ее так, чтобы она находилась подальше от портов, на которых вы находитесь. используя (или просто удалите его полностью).

person ewhac    schedule 29.04.2020