在不阻止主机应用程序的情况下连续读取UART

时间:2016-06-25 00:17:12

标签: c linux multithreading embedded embedded-linux

我一直在寻找并阅读文档,但我正处于需要帮助的地步。用例相对简单,但实现是我被困住的地方。

一端是无线Xbee无线电。该无线电每300ms发送一次信号。该信号的有效载荷包括按钮状态和操纵杆位置。

在接收端是基于Linux的SBC,运行Ubuntu,附带Xbee。为了这篇文章,我将以下内容合并到一个文件中,并添加了一个main以便于阅读:

此代码基于Serial programming Guide

#include <stdio.h>
#include <stdlib.h>
#include <linux/ioctl.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <unistd.h>
#include "XbeeReceiver.h"

#define FALSE 0
#define TRUE 1

volatile int STOP = FALSE;
void signal_handler_IO(int status);
int wait_flag = TRUE;
int fileDescriptor = -1;

/* Constants */
const char *DEFAULT_PORT = "/dev/ttyTHS1";
const int DEFAULT_BAUD = B115200;

/* Prototypes */
struct N64_DTO queryController(int fd);
void init(const char *port, const int baud);
void setTermConfig(int fd, const int baud);
void signal_handler_IO(int status);
int openUART(const char *port);

void init(const char *port, const int baud) {

    fileDescriptor = openUART(port ? port : DEFAULT_PORT);
    setTermConfig(fileDescriptor, baud ? baud : DEFAULT_BAUD);

    while (STOP == FALSE) {
        if (wait_flag == FALSE) {
            struct N64_DTO controller = queryController(fileDescriptor);
            printf("\n\n\n Y Joystick:: %i \n", (signed char) controller.y);
            printf("X Joystick:: %i \n", (signed char) controller.x);
            /* I am supposed to set STOP to TRUE for this loop to stop, however I always want to read from the controller,
             which is why this is now blocking */
            wait_flag = TRUE;
        }
    }
}

struct N64_DTO queryController(int fd) {

    struct N64_DTO controller;
    int byteCount = read(fd, (char *) &controller, sizeof(struct N64_DTO));

    if (byteCount == -1) {
        printf("I'll handle this error later on");
        exit(1);
    }
    return controller;
}

void signal_handler_IO(int status) {
    printf("received SIGIO signal.\n");
    wait_flag = FALSE;
}

void setTermConfig(int fd, const int baud) {

    struct sigaction saio;
    saio.sa_handler = signal_handler_IO;
    sigemptyset(&saio.sa_mask);
    sigaddset(&saio.sa_mask, SIGINT);
    saio.sa_flags = 0;
    saio.sa_restorer = NULL;
    sigaction(SIGIO, &saio, NULL);
    fcntl(fd, F_SETOWN, getpid());
    fcntl(fd, F_SETFL, FASYNC);

    struct termios toptions;

    tcgetattr(fd, &toptions);
    cfsetspeed(&toptions, baud);

    /* man termios for individual definitions */
    toptions.c_cflag &= ~PARENB;
    toptions.c_cflag &= ~CSTOPB;
    toptions.c_cflag &= ~CSIZE;
    toptions.c_cflag |= CS8;
    toptions.c_cflag &= ~CRTSCTS;
    toptions.c_cflag |= CREAD | CLOCAL;
    toptions.c_iflag &= ~(IXON | IXOFF | IXANY);
    toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    toptions.c_oflag &= ~OPOST;
    toptions.c_cc[VMIN] = sizeof(struct N64_DTO);
    toptions.c_cc[VTIME] = 0;

    tcsetattr(fd, TCSANOW, &toptions);
    tcflush(fd, TCIFLUSH);
}

int openUART(const char *port) {

    return open(port, O_RDWR | O_NOCTTY | O_NONBLOCK);
}

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

    int i;
    init("/dev/ttyTHS1", 115200);

    for (i = 0; i < 10; i++) {
        printf("This loop never prints..");
    }

    return 0;
}

虽然它需要更多重构,但这段代码可以正常运行并为我提供预期的输出。然而,现在我有输出,我想用它做一些事情,即作为输入发送到电机控制器等。问题是,由于读取的频率(300ms),程序最终阻止任何其他例程执行。

几周前我回到了绘图板,开始了几条不同的路径。我探索了线程,信号处理程序,利用poll / select API以及创建专用内核模块的可能性。上周,出于不同的原因,我将控制器放在示波器上并设置触发信号的上升沿。那是它袭击我的时候。我想要的是一个事件驱动模型,当特定串行端口上检测到信号时,OS会通知我。我想我会伸手去看看是否有人在这方面有经验,愿意引导我朝着正确的方向前进。我已经在这个问题上待了一个星期,但仍然没有取得任何进展。最后,我们的目标是不断阻止来自端口的串行数据,而不会阻塞我的应用程序的其他部分(驱动电机,移动伺服系统)。

0 个答案:

没有答案