The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]




Версия для распечатки Пред. тема | След. тема
Новые ответы [ Отслеживать ]
Программа работы с Com-портом, типа 'Красная кнопка', !*! apsav, 15-Фев-14, 20:11  [смотреть все]
Доброго времени суток.

Прошу сильно не пинать, если не туда написал - мой первый пост.
Искал готовую программку для работы с Com-портом, для отслеживания замыкания 2 и 3 ноги на нем и по этому событию отработки определенного скрипта. Готового не нашел, поэтому взял с соседнего поста программку для работы с Com-портом и немного переделал под себя. Вот делюсь, вдруг кто-то будет подобное искать...

Программу нужно запускать с правами root, т.к. доступ в Com-порту на запись и чтение по умолчанию имеет только он, либо назначать соответствующие права на файл /dev/ttyS0. Программа запускается, открывает порт, пишет в порт и слушает. Как только замыкаются 2 и 3 нога порта на время более 1 секунды, запускает скрипт, ждет 30 секунд. Есть проблемное место, для меня не критичное, но я на всякий случай предупреждаю о нем: при замыкании контактов программа запускает скрипт дважды, сразу после замыкания контактов и еще раз через 30 секунд. Затем выходит опять в ждущий режим. Но так для меня это не критично, оставил как есть. Для отладки выводит служебную информацию в консоль, которую можно убрать.

#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>

#define PORT "/dev/ttyS0"  //Здесь указывается с каким портом будем работать
#define BAUDRATE B9600     //Скорость работы по порту

int main(){
//int fd = open(PORT, O_RDWR | O_NOCTTY); //"Работа порта с ожиданием прихода данных
// close(fd);
int fd = open(PORT, O_RDWR | O_NDELAY ); //Именно так работает без ожидания com порта на чтение
if (fd<0)
  return 1;
if (!isatty(fd))
  return 2;
struct termios port_cfg;
if (tcgetattr(fd, &port_cfg)<0)
  return 3;
cfmakeraw(&port_cfg);
cfsetospeed(&port_cfg, BAUDRATE);
cfsetispeed(&port_cfg, BAUDRATE);
if (tcsetattr(fd, TCSANOW, &port_cfg)<0)
  return 4;

unsigned int val,val2, a, ret; //инициализация переменных

  val=11111; //задание значения переменных - эти данные будут посылаться в порт
  a=0;//задание значения переменных
   while (a>=0) //начало цикла
{    
   ret = write(fd, &val, 1); // пишем в порт
printf ("ret=%d \n",ret);
printf ("val=%d \n",val);
if (ret!=1)   return 5;
a++,//увеличение значения на 1
printf ("a=%d \n\n",a);
//ret2=0;
//printf ("До чтения ret2=%d \n",ret2);
int ret2 = read(fd, &val2,1); //пытаемся прочитать из порта
printf ("После чтения ret2=%d \n\n",ret2);

if (ret2==1) //Если произошло чтение, то
  {
system ("/home/user/runremote.sh");
printf ("Сработало\n\n");
usleep(30000000); //30 секунд

  }
usleep(1000000);  // 1 секунда
}

return 0;  
close(fd);

}

Есть ли в ней серьезные ошибки? Вроде работает, правда я не программист...

  • Программа работы с Com-портом, типа 'Красная кнопка', !*! Alex_S, 05:23 , 17-Фев-14 (1)
    >

    немного топорно, но сойдет
    пара моментов:

    ты пишешь и читаешь 1 байт  - зачем тебе переменные типа int да еще 11111 ?

    в компортовой системе есть буферы , где могут накапливаться твои записанные байты, вызывая ложное срабатывание 2й раз . Посему если считал 1 байт - хорошо было б почитать еще, пока не вернет 0 , т.е. выгрести все что есть .

  • Программа работы с Com-портом, типа 'Красная кнопка', !*! Alex_S, 05:24 , 17-Фев-14 (2)

    >  return 0;
    >  close(fd);
    > Есть ли в ней серьезные ошибки? Вроде работает, правда я не программист...

    вот эти две строки местами поменяй  :)


  • Программа работы с Com-портом, типа 'Красная кнопка', !*! skb7, 02:20 , 18-Фев-14 (3)
    > Есть ли в ней серьезные ошибки?

    Не уверен насчет серьезности, но если вам нужно сделать code review, то см. ниже

    > #define PORT "/dev/ttyS0"  //Здесь указывается с каким портом будем работать
    > #define BAUDRATE B9600     //Скорость работы по порту
    > system ("/home/user/runremote.sh");

    Я бы сделал передачу этих значений через командную строку. Это можно легко сделать с помощью getopt(). См. man 2 getopt. Я делал так:

    https://gitorious.org/send-arp/send-arp/source/49789e4b75050...

    > int main(){

    Нестандартная сигнатура main(), лучше main(void) сделать, или main(int argc, char *argv[]), если будут обрабатываться параметры командной строки (через getopt() например).

    > while (a >= 0)

    у вас "a" -- это unsigned int, так что "a" никогда не будет меньше нуля. Если нужен вечный цикл -- пишите просто while (1) или for (;;)

    >    unsigned int val,val2, a, ret; //инициализация переменных

    1. область видимости ret можно уменьшить, т.е. внести ret в цикл
    2. это не инициализация, это их объявление (я насчет комментария); комментарии (и строки, которые выводятся на экран тоже) лучше писать на английском языке, кстати: тогда программа будет ASCII файлом, не будет никогда проблем с кодировками, и самое главное -- вашу программу смогут читать все люди на Земле :)

    >         ret = write(fd, &val, 1); // пишем в порт
    >        int ret2 = read(fd, &val2,1); //пытаемся прочитать из порта

    системные вызовы read() и write() возвращают ssize_t, т.е. ret и ret2 должны быть signed. Т.е. уберите unsigned в их декларации.

    >    if (!isatty(fd))
    >        return 2;

    и все остальные return: перед этими return нужно закрывать файловый дескриптор fd.

    Также перед тем, как выйти из программы по ошибке, неплохо бы писать пользователю (в д.с. самому себе), какая ошибка произошла. Писать надо в поток вывода ошибок: fprintf(stderr, ...). Или использовать perror(), если тот вызов при ошибке устанавливает значение errno (надо смотреть маны).

    Ну и еще номера ошибок лучше сделать константами, чтобы не было magic numbers.

    >    val=11111; //задание значения переменных - эти данные будут посылаться в порт

    лучше сделать это константой (например с помощью #define), иначе получается magic number.


    >        a++,//увеличение значения на 1
    >            printf ("a=%d \n\n",a);

    я бы сделал "a++;"
    и да, лучше не ставить таких комментариев, которые дублируют код, они только мешают

    >        printf ("ret=%d \n",ret);
    >        printf ("val=%d \n",val);
    >               printf ("a=%d \n\n",a);

    Здесь выводятся беззнаковые переменные, но используется %d. Для беззнаковых надо использовать %u. Или как вариант -- эти переменные не должны быть беззнаковые.


    >        ret = write(fd, &val, 1); // пишем в порт
    >        if (ret!=1)   return 5;

    в случае ошибки write() всегда вернет -1, лучше на него и проверять (а то измените когда-нибудь кол-во отправляемых байт, и уже не будет работать); и еще перед выходом по этой ошибке лучше через perror() выводить строку ошибки. Тоже самое для всех остальных системных вызовов. Читайте "man 2 write", "man 2 read" и т.д.

    >            usleep(30000000); //30 секунд
    >        usleep(1000000);  // 1 секунда

    Из man 3 usleep:
    POSIX.1-2001 declares this function obsolete; use nanosleep(2)  instead

    >    return 0;
    >    close(fd);

    Наоборот.

    >    return 0;

    лучше вместо 0 использовать EXIT_SUCCESS из stdlib.h.

    Ну что еще можно улучшить -- разбить на функции, чтобы не всё было в main(). Стиль кодирования взять нормальный, например этот: https://www.kernel.org/doc/Documentation/CodingStyle . Неплохо бы ловить и обрабатывать Ctrl+C (SIGINT). А вообще мне кажется что всё это можно было сделать на bash, через stty/echo/cat, или поискать готовую тулзовину. Хотя как пример работы с serial console полезно, только код тогда нужно подрихтовать.

    • Программа работы с Com-портом, типа 'Красная кнопка', !*! skb7, 02:23 , 18-Фев-14 (4)
      И еще маленький совет: заведите себе аккаунт на gitorious.org или github.com и залейте проект туда. Добавьте Makefile и README для него. Может потихоньку улучшите его. Так будет удобней и людям показывать, и сами сможете из любой точки земли его посмотреть/скачать, и при устройстве на работу можно показывать. Может кто-то коммитами поможет и т.д., короче одни выгоды :)
  • Программа работы с Com-портом, типа 'Красная кнопка', !*! pavlinux, 04:28 , 23-Фев-14 (5)
    > Есть ли в ней серьезные ошибки?

    Всё выкинуть, в порт ничё писать не нужно, активность ловить через poll/select.




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру