OpenWRT 上的串行 COM 接口

问题描述 投票:0回答:1

我正在尝试编写一个程序,用于 Teltonika 的 TRB246 上的串行通信(BusyBox v1.34.1)。

传入的数据是原始数据,以十六进制字节为单位,每秒传入一次。

三种解决方案:

  1. 在 shell 脚本中使用
    microcom
    (swift 选项,应该足够了)
  2. 从头开始编写我自己的程序
  3. 尝试定制
    microcom

使用
microcom
:失败

脚本:

#!/bin/sh

ask_dataA='\xFF\x12\xB0\x80\x28\x00\x01\x01\x00\xEA\x00\x00\x00\x00\x77\xA8\x04\xFF'

echo "Asking data A..."
echo -en $ask_dataA > /dev/rs485            # send query
nice -20 microcom -t 1100 -s 9600 /dev/rs485 > tmpsf    # listen
if [ -s tmpsf ]; then                   # checks if file is empty
    hexdump -ve '/1 "%02x"' -n 36 tmpsf         # convert to ascii
    echo ""
else
    echo "nothing"
fi

输出: 在此输入图片描述

有时 if 会按预期给出十六进制答案。

我正在使用 Docklight 监视通信,每条消息都正确且准时地传输。只是 TRB246 没有捕捉到答案。

我想我来得太晚了

microcom
,因为答案在回声后几十毫秒出现。

从头开始编写自己的程序:失败(
read()
无法正常工作),代码:

#include <fcntl.h>
#include <termios.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <errno.h>

#define RS485_DEV       "/dev/ttyS1"
#define RS485_BAUDRATE  B9600
#define RS485_TIMEOUT   0  // in tenths of sec; or use poll() https://man7.org/linux/man-pages/man2/poll.2.html
#define RS485_MINBRD    16 // min bytes to read see http://manpagesfr.free.fr/man/man3/termios.3.html

#define RS485_IBUFFSIZE 32

int main()
{
  printf("Hello guys!\n");
  uint8_t ibuff[RS485_IBUFFSIZE];

  int fd = open(RS485_DEV, O_RDWR | O_NOCTTY | O_NDELAY);

  if (fd == -1) { printf("Failed to open rs485 port: %s\n", strerror(errno)); exit(1); }

  struct termios term_conf;
  struct termios new_term_conf;

  if (tcgetattr(fd, &term_conf) == -1) { printf("Failed to get term config: %s\n", strerror(errno)); } // get current settings

  printf("Former terminal configuration:\n");
  printf("term_conf:\n\tc_iflag = %u\n\tc_oflag = %u\n\tc_cflag = %u\n\tc_lflag = %u\n\n",
        term_conf.c_iflag, term_conf.c_oflag, term_conf.c_cflag, term_conf.c_lflag); 
  for (int i = 0; i < NCCS; i++) { printf("\tc_cc[%d] = %u\n", i, term_conf.c_cc[i]); }
  printf("\n");
    // Configure terminal settings

  // cfmakeraw(&term_conf);
    // Control flags

    // Input flags
    // convert break to null byte, no CR to NL translation,
    // no NL to CR translation, don't mark parity errors or breaks
    // no input parity check, don't strip high bit off,
    // no XON/XOFF software flow control
  term_conf.c_iflag &= ~(IGNBRK | BRKINT | ICRNL | INLCR | PARMRK | INPCK | ISTRIP | IXON); //cfmakeraw adds IGNCR and removes INPCK

    // Output flags
    // no CR to NL translation, no NL to CR-NL translation,
    // no NL to CR translation, no column 0 CR suppression,
    // no Ctrl-D suppression, no fill characters, no case mapping,
    // no local output processing
  term_conf.c_oflag = 0;

    // Local flags
    // echo off, echo newline off, canonical mode off,
    // extended input processing off, signal chars off
  term_conf.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);

    // Chars processing
  term_conf.c_cflag &= ~(CSIZE | PARENB); //clear current char size mask, no parity checking
  term_conf.c_cflag |= CS8;               //force 8 bit input

    //  Others
  printf("term_conf.c_cc[VTIME] = %d, RS485_TIMEOUT = %d, VTIME = %d\n\n", term_conf.c_cc[VTIME], RS485_TIMEOUT, VTIME);
  printf("term_conf.c_cc[VMIN] = %d, RS485_MINBRD = %d, VMIN = %d\n\n", term_conf.c_cc[VMIN], RS485_MINBRD, VMIN);
  term_conf.c_cc[VTIME] = RS485_TIMEOUT;
  printf("term_conf.c_cc[VTIME] = %d, RS485_TIMEOUT = %d, VTIME = %d\n\n", term_conf.c_cc[VTIME], RS485_TIMEOUT, VTIME);
  term_conf.c_cc[VMIN] = RS485_MINBRD;
  printf("term_conf.c_cc[VMIN] = %d, RS485_MINBRD = %d, VMIN = %d\n\n", term_conf.c_cc[VMIN], RS485_MINBRD, VMIN);

  if (cfsetispeed(&term_conf, RS485_BAUDRATE) == -1)  { printf("Failed to set term ispeed: %s\n", strerror(errno)); }
  if (cfsetospeed(&term_conf, RS485_BAUDRATE) == -1)  { printf("Failed to set term ospeed: %s\n", strerror(errno)); }

  tcsetattr(fd, TCSANOW, &term_conf); // apply new conf now 

  tcgetattr(fd, &new_term_conf);      // get conf again
  if (memcmp(&term_conf, &new_term_conf, sizeof(term_conf)) != 0) { // compare to check if changes applied
    printf("Terminal configuration failed\n");
    printf("term_conf:\n\tc_iflag = %u\n\tc_oflag = %u\n\tc_cflag = %u\n\tc_lflag = %u\n\n",\
        term_conf.c_iflag, term_conf.c_oflag, term_conf.c_cflag, term_conf.c_lflag); 
    for (int i = 0; i < NCCS; i++) { printf("\tc_cc[%d] = %u\n", i, term_conf.c_cc[i]); }
    printf("\n");

    printf("new_term_conf:\n\tc_iflag = %u\n\tc_oflag = %u\n\tc_cflag = %u\n\tc_lflag = %u\n\n",\
        new_term_conf.c_iflag, new_term_conf.c_oflag, new_term_conf.c_cflag, new_term_conf.c_lflag); 
    for (int i = 0; i < NCCS; i++) { printf("\tc_cc[%d] = %u\n", i, new_term_conf.c_cc[i]); }
    printf("\n");
    printf("new_term_conf.c_cc[VTIME] = %d, RS485_TIMEOUT = %d, VTIME = %d\n\n", new_term_conf.c_cc[VTIME], RS485_TIMEOUT, VTIME);
    printf("new_term_conf.c_cc[VMIN] = %d, RS485_MINBRD = %d, VMIN = %d\n\n", new_term_conf.c_cc[VMIN], RS485_MINBRD, VMIN);
  }

  // if (ioctl(fd, TIOCEXCL, NULL) == -1)   { printf("Failed to get exclusivity: %s", strerror(errno)); }

  // if (tcflush(fd, TCIOFLUSH) == -1)   { printf("Failed to flush: %s", strerror(errno)); }

  memset(ibuff, 0, RS485_IBUFFSIZE);
  int i = 20000;
  while (i) {
    i--;

    if (read(fd, ibuff, 1) != -1) { printf("%x\n", ibuff[0]); }
    usleep(200);
  }

  close(fd);

  // printf("EAGAIN = %d\n", EAGAIN);

  return 0;
}

输出:

Hello guys!
Former terminal configuration:
term_conf:
    c_iflag = 0
    c_oflag = 0
    c_cflag = 3261
    c_lflag = 0

    c_cc[0] = 3
    c_cc[1] = 28
    c_cc[2] = 127
    c_cc[3] = 21
    c_cc[4] = 16
    c_cc[5] = 0
    c_cc[6] = 0
    c_cc[7] = 0
    c_cc[8] = 17
    c_cc[9] = 19
    c_cc[10] = 26
    c_cc[11] = 0
    c_cc[12] = 18
    c_cc[13] = 15
    c_cc[14] = 23
    c_cc[15] = 22
    c_cc[16] = 4
    c_cc[17] = 0
    c_cc[18] = 0
    c_cc[19] = 0
    c_cc[20] = 0
    c_cc[21] = 0
    c_cc[22] = 0
    c_cc[23] = 0
    c_cc[24] = 64
    c_cc[25] = 235
    c_cc[26] = 119
    c_cc[27] = 0
    c_cc[28] = 0
    c_cc[29] = 0
    c_cc[30] = 0
    c_cc[31] = 100

term_conf.c_cc[VTIME] = 0, RS485_TIMEOUT = 0, VTIME = 5

term_conf.c_cc[VMIN] = 16, RS485_MINBRD = 16, VMIN = 4

term_conf.c_cc[VTIME] = 0, RS485_TIMEOUT = 0, VTIME = 5

term_conf.c_cc[VMIN] = 16, RS485_MINBRD = 16, VMIN = 4

Terminal configuration failed
term_conf:
    c_iflag = 0
    c_oflag = 0
    c_cflag = 3261
    c_lflag = 0

    c_cc[0] = 3
    c_cc[1] = 28
    c_cc[2] = 127
    c_cc[3] = 21
    c_cc[4] = 16
    c_cc[5] = 0
    c_cc[6] = 0
    c_cc[7] = 0
    c_cc[8] = 17
    c_cc[9] = 19
    c_cc[10] = 26
    c_cc[11] = 0
    c_cc[12] = 18
    c_cc[13] = 15
    c_cc[14] = 23
    c_cc[15] = 22
    c_cc[16] = 4
    c_cc[17] = 0
    c_cc[18] = 0
    c_cc[19] = 0
    c_cc[20] = 0
    c_cc[21] = 0
    c_cc[22] = 0
    c_cc[23] = 0
    c_cc[24] = 64
    c_cc[25] = 235
    c_cc[26] = 119
    c_cc[27] = 0
    c_cc[28] = 0
    c_cc[29] = 0
    c_cc[30] = 0
    c_cc[31] = 100

new_term_conf:
    c_iflag = 0
    c_oflag = 0
    c_cflag = 3261
    c_lflag = 0

    c_cc[0] = 3
    c_cc[1] = 28
    c_cc[2] = 127
    c_cc[3] = 21
    c_cc[4] = 16
    c_cc[5] = 0
    c_cc[6] = 0
    c_cc[7] = 0
    c_cc[8] = 17
    c_cc[9] = 19
    c_cc[10] = 26
    c_cc[11] = 0
    c_cc[12] = 18
    c_cc[13] = 15
    c_cc[14] = 23
    c_cc[15] = 22
    c_cc[16] = 4
    c_cc[17] = 0
    c_cc[18] = 0
    c_cc[19] = 0
    c_cc[20] = 0
    c_cc[21] = 0
    c_cc[22] = 0
    c_cc[23] = 161
    c_cc[24] = 7
    c_cc[25] = 64
    c_cc[26] = 0
    c_cc[27] = 168
    c_cc[28] = 152
    c_cc[29] = 232
    c_cc[30] = 119
    c_cc[31] = 104

new_term_conf.c_cc[VTIME] = 0, RS485_TIMEOUT = 0, VTIME = 5

new_term_conf.c_cc[VMIN] = 16, RS485_MINBRD = 16, VMIN = 4

4
fe
4
fe
4
fe
4
fe
4
fe
4
fe

4 和 fe 是我的消息的标准最终字节。即使我更改了函数调用中要读取的 nbytes,我也永远不会得到其他字节。 注意:在 10k 次读取中,它仅返回几个字节。 当没有返回任何内容时,read() 失败并返回 -1,并带有

errno = 11 = EAGAIN
,并且
strerror(errno)
给出 “资源暂时不可用”

我尝试设置 VMIN = 0 和 VTIME = 12(1.2 秒),但是

read()
根本不等待,就像 VTIME = 0 一样。为什么?

尝试定制
microcom

这就是我现在正在寻找的并行解决方案,试图在 BusyBox 中创建一个新程序,但这并不合适......

如果您能就如何使脚本工作或如何解决

read()
问题提供建议,我非常感谢!

embedded-linux openwrt serial-communication rs485
1个回答
0
投票

最后,删除 O_NDELAY 使我能够读取数据,但顺序错误。

设置超时没有帮助(VTIME = 10,VMIN = 0)。而且我的数据顺序错误。

在read()中设置要读取的确切字节数,并让VTIME = 0,VMIN =要读取的确切字节数,彻底解决了问题!

谢谢您的帮助!

© www.soinside.com 2019 - 2024. All rights reserved.