URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 9830
[ Назад ]

Исходное сообщение
"Программа работы с 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 , 17-Фев-14 05:23 
>

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

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

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


"Программа работы с Com-портом, типа 'Красная кнопка'"
Отправлено Alex_S , 17-Фев-14 05:24 

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

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



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

Не уверен насчет серьезности, но если вам нужно сделать 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 , 18-Фев-14 02:23 
И еще маленький совет: заведите себе аккаунт на gitorious.org или github.com и залейте проект туда. Добавьте Makefile и README для него. Может потихоньку улучшите его. Так будет удобней и людям показывать, и сами сможете из любой точки земли его посмотреть/скачать, и при устройстве на работу можно показывать. Может кто-то коммитами поможет и т.д., короче одни выгоды :)

"Программа работы с Com-портом, типа 'Красная кнопка'"
Отправлено pavlinux , 23-Фев-14 04:28 
> Есть ли в ней серьезные ошибки?

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


"Программа работы с Com-портом, типа 'Красная кнопка'"
Отправлено Alex_S , 26-Фев-14 03:58 
>> Есть ли в ней серьезные ошибки?
> Всё выкинуть, в порт ничё писать не нужно, активность ловить через poll/select.

какая там будет активность, если он замкнул тхд с рхд ?



"Программа работы с Com-портом, типа 'Красная кнопка'"
Отправлено pavlinux , 26-Фев-14 16:54 
>>> Есть ли в ней серьезные ошибки?
>> Всё выкинуть, в порт ничё писать не нужно, активность ловить через poll/select.
> какая там будет активность, если он замкнул тхд с рхд ?

Создать :)