пятница, 19 апреля 2013 г.

Работа в Linux с последовательным портом.

Для работы с последовательным портом удобнее всего использовать библиотеки типа boost, но только в том случае, если писать на C++, который на данный момент менее популярен, чем старый добрый C. Еще в преимущества можно добавить тот факт, что понятность кода, использующего синтаксис, созданный пару дестяков лет назад, заметно выше, чем всякие биндинги, плейсхолдеры и модели событийного программиования, которые густо замешаны с шаблонами в библиотеке boost. Простейший пример открытия, чтения и записи см. ниже.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <string.h>
 
int openSerialPort(const char * devName)
{
    //read and write in sync mode
    int hSerial = open(devName, O_RDWR | O_NOCTTY | O_SYNC);
    if(hSerial < 0)
        printf("open device \"%s\" error: %d\n", devName, hSerial);
 
    struct termios port_settings;
    bzero(&port_settings, sizeof(port_settings));
    //
    port_settings.c_cflag |= CREAD;
    port_settings.c_cflag |= CLOCAL;
    //
    port_settings.c_cc[VMIN] = 100;
    //delay, x0.2 sec
    port_settings.c_cc[VTIME] = 2;
    //flush serial port
    int fres = tcflush(hSerial, TCIFLUSH);
    if (fres < 0)
    {
        printf("tcflush() error %d\n", fres);
    }
    //set baud rate
    fres = cfsetispeed(&port_settings, B9600);
    if (fres < 0)
    {
        printf("cfsetispeed() error %d\n", fres);
    }
    fres = cfsetospeed(&port_settings, B9600);
    if (fres < 0)
    {
        printf("cfsetospeed() error %d\n", fres);
    }
    //set character size: 8.
    port_settings.c_cflag &= ~CSIZE;
    port_settings.c_cflag |= CS8;
    //set flow cotrol: none
    port_settings.c_cflag &= ~(CRTSCTS);
    //set parity: none
    port_settings.c_cflag &= ~(PARENB);
    port_settings.c_iflag |= IGNPAR;
    //set stop bits: 1
    port_settings.c_cflag &= ~(CSTOPB);
 
 
    //apply port settings
    fres = tcsetattr(hSerial, TCSANOW, &port_settings);
    if (fres < 0)
    {
        printf("tcsetattr() error %d\n", fres);
    }
    return hSerial;
}
 
int main(int argc, char* argv[])
{
    if(argc < 2) 
    {
        printf("One parameter is omitted\n");
        return -1;
    }
    const char * devName = argv[1]; // "/dev/ttyS0"
    int hSerial = openSerialPort(devName);  
    if(hSerial < 0) 
    {
        return hSerial;
    }        
 
    const char sendVect[5] = {0x01, 0x02, 0x03, 0x04, 0x05};
 
    int byteCount = write(hSerial, sendVect, sizeof(sendVect));
    if (byteCount < 0)
    {
        printf("write error %d\n", byteCount);
    }
 
    char buf[250];
    bzero(buf, sizeof(buf));
 
    byteCount = read(hSerial, buf, sizeof(buf));
    if (byteCount < 0)
    {
        printf("read error %d\n", byteCount);
    }
    else 
    {
        printf("response: \"%s\" \n", buf);
    }     
 
    close(hSerial);
 
    return 0;
}


Как использовать VMIN и VTIME читать здесь:
http://www.unixwiz.net/techtips/termios-vmin-vtime.html

Остальное должно быть ясно из комментариев к коду.