LinuxForum.Fans
Тема

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

Автор: sklimkin 36 сообщений 18445 просмотров
#183646

1. Пожалуйста подскажите, как эта функция/команда для терминала :
$ stty -F /dev/ttyS0 9600
должна выглядеть в файле *.c - в приведенном виде gcc компилятор ее не переваривает.
Искал, но не нашел.
2. Есть причина, по которой я не могу использовать для работы tty0 функции gcc coreutils:
open() read() write(), а только fopen() fread() fwrite().
Мне надо читать бинарный поток из порта блоками, при заранее неизвестном количестве байтов в буфере порта.
Как при этом установить параметры порта (пожалуй только baudrate) не используя struct termios options; ?
Тоже не смог найти.

До темы "первая программа" этому сообщению, как до Китая...

#183723
sklimkin написал:
Пожалуйста подскажите, как эта функция/команда для терминала :
$ stty -F /dev/ttyS0 9600
должна выглядеть в файле *.c

в исходниках stty это описамо максимально подробно...

sklimkin написал:
в приведенном виде gcc компилятор ее не переваривает.

вы написали команду, привидите код...

sklimkin написал:
Есть причина, по которой я не могу использовать для работы tty0 функции gcc coreutils:
open() read() write(), а только fopen() fread() fwrite().

и какая же?

sklimkin написал:
Как при этом установить параметры порта (пожалуй только baudrate) не используя struct termios options; ?

это вопрос из серии "как трахнуть слона синхрофазотроном"...

#183738
Fat-Zer написал:

это вопрос из серии "как трахнуть слона синхрофазотроном"...

Жуть какая!
Зашел сюда, думал, это форум Линускойдов, что-то про программирование будут говорить.
А это оказывается форум ученых. Слониху с сихнрофразотроном скрещивают...
Фигасе, куда ушла наука!

#183762

Для настройки COM-порта есть termios, я всегда пользовался ею.

Пётр.

#183778

Вот файл comport.c - причесать не успел, извините.
Функцию open_port() отключил в main() по вышеуказанной причине.

text
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <signal.h>

#define BUFSIZE 4096

int open_port(void) { int fd; fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY |O_NONBLOCK); if (fd == -1) perror("Open_port: Unable to open /dev/ttyS0"); else { struct termios options; tcgetattr(fd, &options); cfsetispeed(&options, B9600); cfsetospeed(&options, B9600); options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; tcsetattr(fd, TCSANOW, &options); } }

//FILE *fopen("fileout.bin", "w");

void main() { // start Garmin COM-port char GarminStop[8] = {0x10, 0x1C, 0x02, 0x00, 0x00, 0xE2, 0x10, 0x03}; char GarminStart[8] = {0x10, 0x1C, 0x02, 0xFF, 0xFF, 0xE4, 0x10, 0x03}; long BytesRead; int i; int n; FILE* fdout; FILE* fp; char bRead[BUFSIZE]; /* int fd = open_port(); if (fd < 0) //exit(-1); return; */

//stty -F /dev/ttyS0 9600; // port=/dev/tty0 stty -F $port speed 9600 fp = fopen("/dev/ttyS0", "w");

// open port as filepointer FILE* "fp" over filedescriptor "fd" for use func. fread ////fp = fdopen(fd, "w");

printf("\nWARNING! Press Ctrl+C to stop program!\nIt is BINARY %d bytes written to COM-port:\n", 16); ////n = write(fd,GarminStop,8); n = fwrite(GarminStop, sizeof(char), 8, fp); if (n<8) return; ////n = write(fd,GarminStart,8); n = fwrite(GarminStart, sizeof(char), 8, fp); if (n<8) return;

fdout = fopen("fileout.bin", "w"); // open file to output bin-data from COM-port if (!fdout) perror("Open/create out-file: unable to open file!");

// Garmin answer: 10 1c 02 ef bf bd 10 03 10 1c 02 ef bf bd ef bf fread(bRead, BytesRead, BUFSIZE, fp); // read to BUFSIZE bytes from COM-port & write to bRead-array ////BytesRead = read(fd); printf("\nBytes readed %lu\n", BytesRead); for (i=0; i<=BytesRead-2; i++) // find bytes as correspondents to Garmin Messages { if ((bRead[i]==0x10 && bRead[i+1]==0x36 && bRead[i+2]==0x0C) || (bRead[i]==0x10 && bRead[i+1]==0x38 && bRead[i+2]==0x28)) { printf("Bytes readed %lu, found Garmin Message %d\n", BytesRead, (int)bRead[i+1]); break; } else { printf("Bytes readed %lu, NOT found Garmin Message, EXIT!\n", BytesRead); return; } }

// open port - Garmin feature! ////write(fd,GarminStop,8); usleep(1000); write(fd,GarminStart,8); n = fwrite(GarminStop, sizeof(char), 8, fp); usleep(1000); n = fwrite(GarminStart, sizeof(char), 8, fp); usleep(500000); // pause 0.5 sec before reading printf("\n%d Garmin commands is written!\n", 2); // read in cicle by Timer messages from Garmin while (!SIGINT || !VINTR) // if NOT signal = Ctrl+C Ctrl+Break { sleep (1); // in Sec, or maybe in microSec: usleep(1000000); // write to fdout-file, bytes readed, read to BUFSIZE bytes, read from COM-port if (!fread(fdout, BytesRead, BUFSIZE, fp)) ////if (!read(fd)) perror("Read port: none bytes readed from /dev/ttyS0"); } }

//FILE *fopen(const char *path, const char *mode); //return a FILE pointer, or NULL and errno //FILE *fdopen(int fd, const char *mode); //return a FILE pointer, or NULL and errno

//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); //binary stream input //fread() reads nmemb elements of data, each size bytes long, //from the stream pointed to by stream, storing them at the location given by ptr //return the number of items successfully read or 0

//size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); //binary stream output //fwrite() writes nmemb elements of data, each size bytes long, //to the stream pointed to by stream, obtaining them from the location given by ptr //return the number of items successfully written or 0

Последние 10 закомментированных строк - функции, которые мне нужны в работе программы.
Они показывают, что требуется указатель filepointer, а не дескриптор fd
По этой причине я и немогу воспользоваться termios для настройки порта.

А если использовать termios и работать с портом/файлами через дескриптор fd, то нет возможности читать из порта разное (заранее неопределенное) количество байтов, то которое будет в буфере порта каждую следующую секунду (по таймеру sleep(1)).

Если я что-то неправильно понимаю, то поправьте меня.

Fat-Zer пишет: "в исходниках stty это описамо максимально подробно..."

И я читал, но это описано для терминала, а в СИ-исходнике это не работает - компилятор не принимает !!!
Я не нашел как:
$ stty -F /dev/ttyS0 9600
вставить в исходник. В чем и прошу помочь.

А вот что видно в терминае при выполнении скомпилированной программы.
Два варианта - с read write и с fread fwrite:

[console]root@sklimkin-desktop:/home/sklimkin/Рабочий стол/Programming Linux/linux.ru_Programming# ./comport

WARNING! Press Ctrl+C to stop program!
It is BINARY 16 bytes written to COM-port:
����
Bytes readed 0
����
2 Garmin commands is written!
Read port: none bytes readed from /dev/ttyS0: Success
Read port: none bytes readed from /dev/ttyS0: Success
Read port: none bytes readed from /dev/ttyS0: Success
Read port: none bytes readed from /dev/ttyS0: Success
Read port: none bytes readed from /dev/ttyS0: Success
Read port: none bytes readed from /dev/ttyS0: Success
Read port: none bytes readed from /dev/ttyS0: Success
^C
root@sklimkin-desktop:/home/sklimkin/Рабочий стол/Programming Linux/linux.ru_Programming#

After change read & write to fread & fwrite
-------------------------------------------
root@sklimkin-desktop:/home/sklimkin/Рабочий стол/Programming Linux/linux.ru_Programming# ./comport

WARNING! Press Ctrl+C to stop program!
It is BINARY 16 bytes written to COM-port:

Bytes readed 0

2 Garmin commands is written!
Read port: none bytes readed from /dev/ttyS0: Success
Read port: none bytes readed from /dev/ttyS0: Success
Read port: none bytes readed from /dev/ttyS0: Success
Read port: none bytes readed from /dev/ttyS0: Success
Read port: none bytes readed from /dev/ttyS0: Success
Read port: none bytes readed from /dev/ttyS0: Success
Read port: none bytes readed from /dev/ttyS0: Success
Read port: none bytes readed from /dev/ttyS0: Success
Read port: none bytes readed from /dev/ttyS0: Success
^C
root@sklimkin-desktop:/home/sklimkin/Рабочий стол/Programming Linux/linux.ru_Programming#
[/console]

#183784

И с termios можно читать неопределённое количество байтов из порта,
прочитайте внимательнее в "man termios" описание параметров VMIN и VTIME.
Уж как это реализовать, сообразите сами. Зависит ещё от конкретной задачи.
Если же не ищете лёгких путей, посмотрите "man system".

Пётр.

#183790

для начала из open_port() забыли дескриптор вернуть... а сейчас не работает, ибо порт не настроен...

#183792
zhevak написал:
[quote=Fat-Zer]
это вопрос из серии "как трахнуть слона синхрофазотроном"...

Жуть какая!
Зашел сюда, думал, это форум Линускойдов, что-то про программирование будут говорить.
А это оказывается форум ученых. Слониху с сихнрофразотроном скрещивают...
Фигасе, куда ушла наука![/quote]
Юмор -вещь хорошая.
Не судите строго:
1. я только присматриваюсь к Линуксу
2. я не программист, а геодезист
3. лет 5 использовал VBA для AutoCAD'а и этого мне хватало
4. СИ немного знаю и использую только в виде Pelles-C (Win) в течение последних 1.5 лет
5. читал Ваши статьи на форуме (простите забыл название) по toolchain для AVR и ARM процессоров - очень интересно, а также по работе с COM-портом - поэтому рассчитывал и на Ваши подсказки тоже
6. и наконец я точно знаю, что многие после 60-ти лет начинают туговато соображать (мне 61 год)

Поэтому прошу прощения за глупые по Вашему мнению вопросы и прошу практичесих советов.

#183794

Спасибо за ответы Fat-Zer и Пётр, буду еще раз внимательно читать.
С непривычки рябит в глазах при чтении man и info вот и не схватываю (да и английский для меня Fremdschprache).

#183796

И все же: господа Линукс-программеры!
Как должна выглядеть в СИ файле строка изменения характеристик терминала tty
Вот цитата из coreutils.info - она работает в терминале но до моего сознания без примера на СИ не доходит:

File: coreutils.info, Node: stty invocation, Next: printenv invocation, Prev: pwd invocation, Up: Working context
19.2 `stty': Print or change terminal characteristics
=====================================================
`stty' prints or changes terminal characteristics, such as baud rate.
Synopses:
stty [OPTION] [SETTING]...
stty [OPTION]

Мне пока нужно установить скорость порта в 9600 бод и все!

#183798

sklimkin, вы поймите, что си это не скрипты и нельзя просто так вызвать другую программу...

text
    
    cfsetispeed(&options, B9600);
    cfsetospeed(&options, B9600);
    tcsetattr(fd, TCSANOW, &options);

в принципе open_file() у вас написано правильно, просто не забывайте вернуть дескриптор... и этими строчками вы как раз и устанавливаете скорость в 9600бод. остальные параметры - это контроль чётности и что-то ещё... какие вам они нужны я не знаю...

#183804
sklimkin написал:

Юмор -вещь хорошая.
Не судите строго:
1. я только присматриваюсь к Линуксу
2. я не программист, а геодезист
3. лет 5 использовал VBA для AutoCAD'а и этого мне хватало
4. СИ немного знаю и использую только в виде Pelles-C (Win) в течение последних 1.5 лет
5. читал Ваши статьи на форуме (простите забыл название) по toolchain для AVR и ARM процессоров - очень интересно, а также по работе с COM-портом - поэтому рассчитывал и на Ваши подсказки тоже
6. и наконец я точно знаю, что многие после 60-ти лет начинают туговато соображать (мне 61 год)

Поэтому прошу прощения за глупые по Вашему мнению вопросы и прошу практичесих советов.

Да, я, в общем-то, и не сужу строго. Точнее -- вообще стараюсь не судить и не осуждать.
Чтобы судить, нужно хорошо знать то (и того), что судишь.
И даже в некоторой степени чувствую, что мне надо извинится за то, что влез со своей шуткой. Ничего дурного не преследовал. Уж больно образ забавный был...

1. И очень хорошо делаете.
2. Прекрасно. Геодезия -- отличное направление деятельности. Вообще, в мире столько всего интересного...
3. :)
4. Дак, все нормально! Я вот тоже, собираюсь на днях заняться не своей деятельностью. Нужно вварить в трубы счетчики для ХВС/ГВС. Трубы полипропиленовые. Сантехники заряжают суммы от 1000 до 2700 рублей за работу. Зашел в магазин, приценился к паяльнику -- 2250 рублей. Ну... как бы если я себе и маме в квартиру поставлю счетчики сам, то я уже отобью стоимость паяльника. Трубы стоят от 20 до 40 рублей. За такие деньги можно и потренироваться. Не думаю, что сантехники обладают каким-то особым знанием в сварке труб. Вы скажите типа "а вдруг потечет? Затопишь соседей. Обойдется дороже". Ага. Ответственность называется. Вварили эти горе-сантехники тут трубу в ванной комнате... Теперь труба шишками покрылась -- где эти сантехники? С кого спрашивать? Что так, что так все равно риск мой. Так уж лучше я сам сделаю так как мне надо. Видал я этих "мастеров" граненого стакана! Нафиг! Руки не крюки. Осилим и это. Чего и Вам желаю!
5. Спасибо за добрые слова. Тронут.
Там же на форуме, где Вы читали про тулчейны, есть пост про работу последовательным портом. Месяц назад меня попросили подсказать. Вот он пост -- http://forum.e-lug.ru/viewtopic.php?id=660 Посмотрите, вдруг чем-то поможет.
6. 61 -- это, как говорят нынче молодые, -- это всяческий респект и уважуха! Не сдавайтесь! Я против Вас -- мальчишка.

Вспоминаю, какой-то старый эпизод из зомбоящика. За давностью времени уже не помню даже деталей события, не то что имен. Ну, не важно! Рассказывает какой-то мужчина средних лет, как он, будучи студеном, случайно стал свидетелем какого-то спора, который разгорелся на кафедре в институте между двумя старыми-старыми преподавателями. Обоим было уже далеко за 70. В общем разговаривали они на повышенных тонах. Один другому все время кричал:
-- Да ты сопляк! Ты ничего не понимаешь в этом! Мальчишка!
Второй вроде как возражал, но относительно уважительно относился с собеседнику.
У студента любопытство возымело верх. Он приблизился к ним и задал вопрос:
-- Простите, а почему Вы так на него -- "Мальчишка!", "Сопляк!". Вы ж ведь оба старые и уважаемые люди? Какой он вам мальчишка?
-- Да он мальчишка и есть!
-- Э-э... не понял...
-- Он моложе меня на 10 лет! Я его из соски кормил!
:lol:

#183815

Чтение из последовательного порта -- это крайне занятная штука.

В Линуксе не имеет значения с каким контентом вы работаете -- бинарные данные или тект. В Венде разница есть. В Венде в текстовых файлах производится обработка символа конца строки '\n'. При передаче в одну строну (запись в файл) вместо одного байта ("\n") в поток вставляется два байта ("\n\r"). При передаче обратно (из файла в оперативную память компа) -- один байт удаляется. Ну, что сделать... программисты Майкрософт такие затейники! Такие затейники! Ну, не важно!

Чтение потока данных из последовательного порта характеризуется множеством самых разных неопределенностей, которые как-то надо предусматривать в своей программе. Например, вы не можете заранее знать, сколько байт находится в приемном буфере последовательного интерфейса. Это порождает целую гроздь вопросов -- что делать, если мы запросили 10 байт, а там их 9? Или вообще ни одного еще не поступило? Что должна делать наша программа? Мы вызвали библиотечную функцию fread, и функция не будет возвращать управление в нашу программу до каких пор? Пока не насобирает все 10 байт? Или пока не истечет время ожидания?

Отвечая себе на кучу вот таких вопросов, нужно смоделировать поведение нашей программы. Потом это "поведение" мы задаем в параметрах структуры struct termios.

Вообще, работа с параллельным портом (с сетевыми соединениями, да и вообще практически с любым интерфейсом!) подразумевает работу в программе нескольких потоков. И в самом деле, если прога "зависнет", на функции чтения, то она не сможет своевременно отработать команды пользователя. Тоже ведь не хорошо. Поэтому по всем правилам нужно иметь один главный поток (для взаимодействия с юзером) и несколько вспомогательных, которые, например, поставляют данные основному. Приняв или передав данные они сообщают основному о готовности.

В небольших программах допустимо все делать в одном потоке. Никто не запрещает вам читать из потока по одному байту. Забирайте данные по одному байту и складывайте их в свой буфер. Буфер заполнился -- обработайте. Потом снова в цикл сбора. Главное, не как сделано. Главное, что оно вообще начало работать. А мастерство, как это делать по науке, придет потом!

Удачи!

#183861
zhevak написал:
Чтение из последовательного порта -- это крайне занятная штука.

В Линуксе не имеет значения с каким контентом вы работаете -- бинарные данные или тект.
...
Чтение потока данных из последовательного порта характеризуется множеством самых разных неопределенностей, которые как-то надо предусматривать в своей программе. Например, вы не можете заранее знать, сколько байт находится в приемном буфере последовательного интерфейса. Это порождает целую гроздь вопросов -- что делать, если мы запросили 10 байт, а там их 9? Или вообще ни одного еще не поступило? Что должна делать наша программа? Мы вызвали библиотечную функцию fread, и функция не будет возвращать управление в нашу программу до каких пор? Пока не насобирает все 10 байт? Или пока не истечет время ожидания?
...
Отвечая себе на кучу вот таких вопросов, нужно смоделировать поведение нашей программы. Потом это "поведение" мы задаем в параметрах структуры struct termios.
...
В небольших программах допустимо все делать в одном потоке. Никто не запрещает вам читать из потока по одному байту. Забирайте данные по одному байту и складывайте их в свой буфер. Буфер заполнился -- обработайте. Потом снова в цикл сбора. Главное, не как сделано. Главное, что оно вообще начало работать. А мастерство, как это делать по науке, придет потом!
Удачи!

Вы знаете у меня программы работы с приемниками/навигаторами по бинарному протоколу (бо именно он есть профессионального содержания/наполнения) Garmin и SirfStar, разбираются в чипсетах SirfStar-II и SirfStar-III, записывают в выходные файлы: бинарный поток, парсинг бинарных данных в Human-представлении, RINEX-файл observation, ну и так по-мелочи еще.
И окошечки-кнопочки научился "рисовать" вручную - так надежней и понятней что делаешь и что будет делать твоя программа.
Но все это в Win-32, а сейчас я хочу "перенести" это в Линукс, при этом как и в Win-32 хочу обойтись без классов и объектов (ну не нравится мне MFC) - т.е. намерен писать на ПРОСТО-СИ, опираясь на стандартные библиотеки системы.
К слову сказать под Вайном программы мои работают штатно.

Это я к тому, что худо-бедно понимаю предмет.
Не верится мне, что в сишных библиотеках ОС Линукс для компилятора gcc нет того, что есть в ней же для bash и терминала.
Уже сейчас вижу, что система намного боГАче, чем Виндовс.

Вот только с "описаловом" некоторые накладки. Но это лечится. Например:
Я здесь задал вопросы и показал код (пусть он еще очень сырой), надеясь на подсказки профессионалов.
И никто не сказал, что read() (в отличие от того что есть в man read) может принимать до 3-х аргументов примерно так BytesRead = read(fd, bRead, BUFSIZE);
Нашел я объяснения в документе 10-летней давности:
Serial Programming HOWTO Gary Frerking gary@frerking.org Peter Baumann ну и так далее...

Спасибо за напутствие, и Вам не хворать!

Разберусь конечно и с консольным и с оконным написанием программы (Code:Blocks для начала).
Не хотелось тормозить на нюансах, которые программистам с опытом давно известны. Но старт - он и в Африке старт.

С исходник внес некоторые исправления по подсказкам Fat-Zer и Петра, за что им еще раз спасибо.
Кто может посмотреть и еще раз подсказать, почему ничего не читается из порта?
Я наверняка знаю, что после 2-х 8-байтовых команд навигатор льет в порт бинарный поток.

text
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <signal.h>

#define BUFSIZE 4096

int open_port(void) { int fd; fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY |O_NONBLOCK); if (fd == -1) perror("Open_port: Unable to open /dev/ttyS0"); else { struct termios options; tcgetattr(fd, &options); cfsetispeed(&options, B9600); cfsetospeed(&options, B9600); options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; // 2 strings added by SNK ////cc_t c_cc[s] VMIN = 1; options.c_cc[VMIN] = 1; ////cc_t c_cc[s] VTIME = 1; options.c_cc[VTIME] = 1; tcsetattr(fd, TCSANOW, &options); } return fd; // было пропущено!!! }

//FILE *fopen("fileout.bin", "w");

void main() { // start Garmin COM-port char GarminStop[8] = {0x10, 0x1C, 0x02, 0x00, 0x00, 0xE2, 0x10, 0x03}; char GarminStart[8] = {0x10, 0x1C, 0x02, 0xFF, 0xFF, 0xE4, 0x10, 0x03}; int BytesRead; int i, n; FILE* fdout; ////FILE* fp; char bRead[BUFSIZE];

int fd = open_port(); if (fd < 0) return;

//stty [-F DEVICE | --file=DEVICE] [SETTING] //Special settings: ispeed N - set the input speed to N, ospeed N - set the output speed to N, //min N with -icanon, set N characters minimum for a completed read //time N with -icanon, set read timeout of N tenths of a second //speed print the terminal speed //stty -F /dev/ttyS0 ispeed 9600 min 1 time 1 // ???

////fp = fopen("/dev/ttyS0", "w");

printf("\nWARNING! Press Ctrl+C to stop program!\nIt is BINARY %d bytes written to COM-port:\n", 16); n = write(fd,GarminStop,8); ////n = fwrite(GarminStop, sizeof(char), 8, fp); if (n<8) return; n = write(fd,GarminStart,8); ////n = fwrite(GarminStart, sizeof(char), 8, fp); if (n<8) return;

fdout = fopen("fileout.bin", "w"); // open file to output bin-data from COM-port if (!fdout) perror("Open/create out-file: unable to open file!");

// Garmin answer must bee ca.: 10 1c 02 ef bf bd 10 03 10 1c 02 ef bf bd ef bf ////fread(bRead, BytesRead, BUFSIZE, fp); // read to BUFSIZE bytes from COM-port & write to bRead-array BytesRead = read(fd, bRead, BUFSIZE); // res = read(fd,buf,255); printf("\nBytes readed %d\n", BytesRead); if (BytesRead>2) { for (i=0; i<=BytesRead-2; i++) // find bytes as correspondents to Garmin Messages { if ((bRead[i]==0x10 && bRead[i+1]==0x36 && bRead[i+2]==0x0C) || (bRead[i]==0x10 && bRead[i+1]==0x38 && bRead[i+2]==0x28)) { printf("Bytes readed %d, found Garmin Message %d\n", BytesRead, (int)bRead[i+1]); break; } else { printf("Bytes readed %d, NOT found Garmin Message, EXIT!\n", BytesRead); return; } } } else { printf("None answer from Garmin-device. End of program!\n"); return; }

// open port - Stop_&_Start commands is feature of all Garmin receivers/navigators! write(fd,GarminStop,8); usleep(1000); write(fd,GarminStart,8); ////n = fwrite(GarminStop, sizeof(char), 8, fp); usleep(1000); n = fwrite(GarminStart, sizeof(char), 8, fp); usleep(500000); // pause 0.5 sec before reading printf("\n%d Garmin commands is written!\n", 2); // read in cicle by Timer messages from Garmin while (!SIGINT || !VINTR) // if NOT signal = Ctrl+C Ctrl+Break { sleep (1); // in Sec, or maybe in microSec: usleep(1000000); // write to fdout-file, bytes readed, read to BUFSIZE bytes, read from COM-port ////if (!fread(fdout, BytesRead, BUFSIZE, fp)) if (!fd, bRead, BUFSIZE)) perror("Read port: none bytes readed from /dev/ttyS0"); } } // End main()

#183895

Мне сейчас некогда смотреть, но могу сказать, что для чтения из COM-порта
я всегда делал свою небольшую подпрограмму с параметрами типа количества
читаемых байтов, признака конца посылки и уже из неё вызывал read и анализировал
то, что приходит. Например, в зависимости от протокола связи начальные
символы тоже могут быть предопределёнными, также в начале посылки может
передаваться её длина. У read не до трёх, а именно три аргумента.

Пётр.

#183937

Здравствуйте, sklimkin!

Пожалуйста, назовите свое имя, а то обращаться по нику как-то "неуютно".

Сейчас сижу, разбираюсь с Вашими Листингами. Сейчас будет много вопросов с моей строны. Готовьтесь плотно поработать.

Пока обратил внимание на то, что у Вас в распечатке с консоли присутствует знак #. Вы работете под рутом, это не есть хорошо. Потом я подскажу как Вам можно работать с последовательным портом не повышая своего статуса до рута.

А пока жду, Вашего выхода на связь и пытаюсь понять, что должна делать Ваша прога.

#184073

To zhevak: sklimkin - Сергей Климкин.
Интернетовские nikname очень напоминают кликухи у урок, но что делать если так принято уже.
Вы кстати тоже не представились.
Я конечно немного погорячился, но менторские нотки мало кого оставляют равнодушным.

А теперь по делу.
Программу поправил: как часто бывает от спешки были 2 досадные ошибки, я их не сразу увидел.
Программка работает, то есть:
1. открывает порт
2. открывает файл для вывода
3. соединяется с устройством (Гармин-навигатором) на другом конце провода
4. читает из порта
5. пишет в файл вывода

Меня порадовал размер исполняемого файла 7.5 кБ (проверил в CodeLite - то же самое).
В этом тесте мне не удалось использовать read() -- write() и fread() -- fwrite() в одной программе.
Но если в Винде это возможно, то в Линуксе тем более (думаю я пока).
Первое беглое знакомство с man-ами и info-ми не порадовало, ну не MSDN это (хотя и в MSDN'е опухнешь искать нечто маленькое и редко надобное).
А вот документирование программ прежними Юниксоидами вызвало восхищение (когда и как успевали?).
Шокирующее впечатление от дебагера в Code::Blocks v. 8.5 (а новый v. 10.x не устанавливается в моей Юбунте).
Поскольку к рюшечкам у меня пиетета нет, то думаю для обычных окон-кнопок-боксов подойдет CodeLite или geany.
В любом случае придется переучиваться с Win-IDE на Lin-IDE.

Я не поблагодарил Ден Зурин за его подсказку на страничке http://linuxforum.ru/viewtopic.php?id=8328&p=2 о том как начинающим быстро и просто скомпилировать и выполнить свою 1-ю программу, а ведь без этой подсказки я еще долго собирался бы начать работать в Линуксе.
Теперь есть увереннность, что можно переходить. Получение быстрого положительного результата вдохновляет (психология однако!).

Консоль консолью, а все же окошки позволяют быстро и удобно настроить рабочие параметры программы с помощью тех же комбо- и прочих боксов и выводить текущую инфо в разные label и прочие элементы, а также быстро переходить из окна в окно (из закладки в закладку).

По поводу рута и усера в Линуксе внимательно Вас выслушаю. Пока не понимаю, зачем быть пользователем на своем домашнем компьютере, тем более что многие экзальтированные линуксоиды кричат о том что нет вирусных угроз в Линуксе - "это вам не то (Windows)".
Наверное я пока не вижу других проблем от такого пользования, ну и привычки от Win-XP.

Выложу последний вариант кода comport.c и спасибо тем, кто помог разобраться с теми функциями, которые были (есть) критичными для меня в вопросе перехода на Линукс. Кстати хочу заметить (не Вам zhevak), что COM-порт LPT-порт до сих пор и востребованы и юзабельны, но в профессиональных а не офисных кругах. Более современные интерфейсы как то USB BT WF имеют свои не сразу видимые недостатки, а скорость передачи данных не везде и не всегда нужна выше 115кБит/сек (например спутниковая навигация использует диапазон 4.8--57кБит/сек).

text
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>

#define BUFSIZE 4096

int open_port(void) { int fd; fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY |O_NONBLOCK); if (fd == -1) perror("Open_port: Unable to open /dev/ttyS0"); else { struct termios options; tcgetattr(fd, &options); cfsetispeed(&options, B9600); cfsetospeed(&options, B9600); options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; // 4 strings added by SNK options.c_cc[VMIN] = 1; // minimum bytes options.c_cc[VTIME] = 1; // interval in 1/10 sec options.c_lflag = ICANON; // enable canonical input options.c_oflag = 0; // raw output tcsetattr(fd, TCSANOW, &options); } return fd; // было пропущено!!! }

//FILE *fopen("fileout.bin", "w");

void main() { // start Garmin COM-port char GarminStop[8] = {0x10, 0x1C, 0x02, 0x00, 0x00, 0xE2, 0x10, 0x03}; char GarminStart[8] = {0x10, 0x1C, 0x02, 0xFF, 0xFF, 0xE4, 0x10, 0x03}; int BytesRead; int i, n, ifound; ////FILE* fdout; int fdout; ////FILE* fp; char bRead[BUFSIZE];

int fd = open_port(); if (fd < 0) return;

printf("\nWARNING! Press Ctrl+C to stop program!\nIt is BINARY %d bytes written to COM-port:\n", 16); n = write(fd,GarminStop,8); if (n<8) return; n = write(fd,GarminStart,8); if (n<8) return;

fdout = open("fileout.bin", O_WRONLY | O_CREAT | O_TRUNC); if (!fdout) perror("Open/create out-file: unable to open file!"); sleep (2); // in Sec BytesRead = read(fd, bRead, BUFSIZE); // res = read(fd,buf,255); printf("\nBytes readed %d\n", BytesRead); if (BytesRead>2) { for (i=0; i<=BytesRead-2; i++) // find bytes as correspondents to Garmin Messages { if ((bRead[i]==0x10 && bRead[i+1]==0x36 && bRead[i+2]==0x0C) || (bRead[i]==0x10 && bRead[i+1]==0x38 && bRead[i+2]==0x28)) { printf("Bytes readed %d, found Garmin Message %d\n", BytesRead, (int)bRead[i+1]); ifound = 1; break; } } if (ifound==0) { printf("Bytes readed %d, NOT found Garmin Message, EXIT!\n", BytesRead); return; }

} else { printf("None answer from Garmin-device. End of program!\n"); return; }

// open port - Stop_&_Start commands is feature of all Garmin receivers/navigators! write(fd, GarminStop, 8); usleep(1000); write(fd, GarminStart, 8); usleep(500000); // pause 0.5 sec before reading printf("\n%d Garmin commands is written!\n", 2); // read in cicle by Timer messages from Garmin while (!SIGINT || !VINTR) // if NOT signal = Ctrl+C Ctrl+Break { sleep (1); // in Sec, or maybe in microSec: usleep(1000000); // write to fdout-file, bytes readed, read to BUFSIZE bytes, read from COM-port BytesRead = read(fd, bRead, BUFSIZE); if (BytesRead<1) perror("Read port: none bytes readed from /dev/ttyS0"); else { n = write(fdout, &bRead[0], BytesRead); printf("%d bytes written Garmin Messages\n", n); } } } // End of main()

Хотел приаттачить сюда картинку, но не смог.
Подскажите, как картинка *.png или *.jpg с моего компьютера должна попасть сюда через кнопочку "img"

Вот лог программы в терминале:
[console]root@sklimkin-desktop:/home/sklimkin/Рабочий стол/Programming Linux/linux.ru_Programming# make
gcc -o comport comport.c
root@sklimkin-desktop:/home/sklimkin/Рабочий стол/Programming Linux/linux.ru_Programming# ./comport

WARNING! Press Ctrl+C to stop program!
It is BINARY 16 bytes written to COM-port:

Bytes readed 73
Bytes readed 73, NOT found Garmin Message, EXIT!
root@sklimkin-desktop:/home/sklimkin/Рабочий стол/Programming Linux/linux.ru_Programming# ./comport

WARNING! Press Ctrl+C to stop program!
It is BINARY 16 bytes written to COM-port:

Bytes readed 28
Bytes readed 28, found Garmin Message 54

2 Garmin commands is written!
4 bytes written Garmin Messages
68 bytes written Garmin Messages
46 bytes written Garmin Messages
8 bytes written Garmin Messages
33 bytes written Garmin Messages
45 bytes written Garmin Messages
46 bytes written Garmin Messages
21 bytes written Garmin Messages
2 bytes written Garmin Messages
Read port: none bytes readed from /dev/ttyS0: Success
2 bytes written Garmin Messages
12 bytes written Garmin Messages
59 bytes written Garmin Messages
Read port: none bytes readed from /dev/ttyS0: Success
33 bytes written Garmin Messages
31 bytes written Garmin Messages
83 bytes written Garmin Messages
35 bytes written Garmin Messages
141 bytes written Garmin Messages
2 bytes written Garmin Messages
56 bytes written Garmin Messages
Read port: none bytes readed from /dev/ttyS0: Success
33 bytes written Garmin Messages
43 bytes written Garmin Messages
3 bytes written Garmin Messages
50 bytes written Garmin Messages
53 bytes written Garmin Messages
47 bytes written Garmin Messages
173 bytes written Garmin Messages
21 bytes written Garmin Messages
2 bytes written Garmin Messages
Read port: none bytes readed from /dev/ttyS0: Success
10 bytes written Garmin Messages
4 bytes written Garmin Messages
59 bytes written Garmin Messages
33 bytes written Garmin Messages
62 bytes written Garmin Messages
3 bytes written Garmin Messages
116 bytes written Garmin Messages
^C
root@sklimkin-desktop:/home/sklimkin/Рабочий стол/Programming Linux/linux.ru_Programming#
[/console]

#184079
sklimkin написал:
В этом тесте мне не удалось использовать read() -- write() и fread() -- fwrite() в одной программе.

ИМХО самый простой способ в данном случае - это открыть файл открыть файл через open(), а потом поток через fdopen().

sklimkin написал:
Подскажите, как картинка *.png или *.jpg с моего компьютера должна попасть сюда через кнопочку "img"

сначала надо загрузить их куда-либо в интернет(например на itmages.ru), а затем:

text
[img]<адрес изображения>[/img]

или можно просто код скопировать BB-код оттуда...

#184089

Я так и знал, что образуются две параллельных ветки. Но не делать параллельную ветку было бы хуже. Поэтому и делал.

Публикую свою ветку только потому, что тут (как лично мне кажется) есть чему поучиться.
Собственно, я и хотел поделиться своим опытом написания программ. Я не претендую на абсолютно правильный стиль. У каждого писателя (программиста он свой). Просто есть некоторые моменты, на которые хотелось бы обратить внимание.

Прога не рабочая. Я даже ее еще не компилировал. Тем более в проге нет никакой логики. Ее-то я и хотел от вас получить.

text
// Состав Инклюдов еще не пересматривал. Добвил только strinh.h для функции memcpy
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>

// Этот дефайн и все, что с ним связано, тоже не перетряхал. #define BUFSIZE 4096

// Имя последовательного порта. Вынесем его в отдельную переменную. // Преимущество этого состоит в том, что имя определено в одном месте, и если в жизни что-то // измениться, то править это нужно будет только в одном месте. Например, приспичит работать // по USB-порту с переходником USB-RS232, тогда смело заменяем на "/dev/ttyUSB0". const char *serport = "/dev/ttyS0";

// Тоже самое для выходного файла. Вдруг потом взбредет в голову задавать имя файла в // командной строке при запуске программы. // "const" -- не позволит программе "случайно" повредить константное имя const char *fileout = "info-from-garmin.bin";

// Две команды Garmina. Это два константых набора байтов. Они не "завязаны" на функцию main, // поэтому, их лучше определить глобально. Вдруг потом понадобится создать еще один // программный модуль или файл. Тогда их будет легче портировать отсюда, а не искать по тексту // и выковыривать из функций.

// Такое определение просто. Его очень часто используют. #define STARTSIZE const uint8_t GarminStart[STARTSIZE] = {0x10, 0x1C, 0x02, 0xFF, 0xFF, 0xE4, 0x10, 0x03};

// А это определение -- более навороченное: // Команда Stop и размер команды, который автоматически (то бишь -- компилятором) // определяется по факту, а не задается руками. Таким образом, можно добавлять или убавлять // количество байт в команде и не заботиться, что нужно изменить их количество. const uint8_t GarminStop[] = {0x10, 0x1C, 0x02, 0x00, 0x00, 0xE2, 0x10, 0x03}; const uint8_t sizeStop = sizeof(GarminStop) / sizeof(uint8_t);

// Я написал эти два определния по разному только ради примера. Так делать не рекомендуется: // смешение стилией программирования -- не есть хорошо. Вам нужно для себя принять какой-нибудь // один и следовать ему на протяжении программы.

// Эту фкнкцию пока не трогал int open_port(void) { int fd;

fd = open(serport, O_RDWR | O_NOCTTY |O_NONBLOCK); if (fd == -1) perror("Open_port: Unable to open /dev/ttyS0"); else { struct termios options; tcgetattr(fd, &options); cfsetispeed(&options, B9600); cfsetospeed(&options, B9600); options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; tcsetattr(fd, TCSANOW, &options); } }

//--------------------------------------------------------------------------------------------- // Найти последовательность sample в buf // Возвращаемое значение: // при успехе, функция возвращяет смещение до искомой последовательности относительно // начала буфера. Если последовательность не найдена -- функция возвращает -1 int lookfor(uint8_t *buf, int bufsize, uint8_t *sample, int samplesize) { int i; // Размер буфера должен быть всяко больше размера того, что в нем ищем if (bufsize < samplesize) return -1; // Будем считать, что не нанашли for (i = 0; i < bufsize - ; i++) if (memcmp(&buf[i], sample, samplesize) == 0) return i; // Нашли!!! return -1; // Не найдено. }

//--------------------------------------------------------------------------------------------- // void main(void) { long BytesRead; int i; int n, nbytes; FILE* fdout; FILE* fp;

// Используйте правильный размер переменных. Обмен осуществляется байтами -- вот и указывайте // байтовую переменную. "char" -- это не обязательно байт! uint8_t bRead;

//stty -F /dev/ttyS0 9600; // port=/dev/tty0 stty -F $port speed 9600 fp = fopen(serport, "w"); // Как только написали эту функцию, сразу же напишите функцию fclose и проверку, что fopen // вернула. После этого дописывайте функционал (ну те действия, котрые должна выполнять // Ваша прога) между fopen и fclose // Если хотите писать надежные программы, то обязательно проверяйте то, что возвращают // функции. В данном случае -- вдруг такого порта в компе не окажется? if (fp == NULL) { // Недостающие уточнения функция perror допишет сама к нашей строке. perror("Открытие последовательного порта"); // exit закроет все открытые дескрипторы файлов и закончит работу программы. exit(EXIT_FALURE); }

// Мы открываем/создаем файл, в который будем записывать принимаемую из последовательного // порта информацию. Будет более правильно, если мы сначала откроем файл, а потом выдадим // команды Stop/Start в последовательный порт. // Если мы не сможем открыть/создать файл, то какой смысл посылать команды во внешний мир? fdout = fopen(fileout.bin, "w"); if (!fdout) { perror("Файл полученных данных от Garmin-а"); exit(EXIT_FALURE); }

// Нам нужно выслать один блок данных. Размер блока 8 байт. // Можно поступить по другому. Выслать 8 блоков данных, размер которых один байт. Но это будет // не совсем корректно с точки зрения логки -- высланная половина блока никому не нужна, // как не нужена половина собаки, которую перехал трамвай. n = fwrite(GarminStop, sizeStop, 1, fp); if (n != 1) { perror("Запись команды Stop в порт"); exit(EXIT_FALURE); } n = fwrite(GarminStart, STARTSIZE, 1, fp); if (n != 1) { perror("Запись команды Start в порт"); exit(EXIT_FALURE); }

// В этой точке программы у нас открыт файл для записи данных, открыт последовательный порт и // в через него отправлены две команды в устройство. Сейчас нам предстоит считывание // получаемых данных из устройства. Поскольку мы заранее не знаем, солько байт оно нам // пошлет, то будем читаь по обному байту. (Мы хотим получить из устройства пять байт, а оно // сломалось и послало нам только два байта. Что будем делать? Очень долго ждать недостающие // трибайта? И как долго?)

// Сейчас самое время сообщить пользователю о сволих намерениях printf("\nНажмите на Ctrl+C для выхода из программы.\n") // Garmin answer: 10 1c 02 ef bf bd 10 03 10 1c 02 ef bf bd ef bf n = fread(bRead, 1, 1, fp); // Читаем по одному байту! // Диагностические штучки типа этой лучше выделять. Нужно еще кое-что дописать. // Не готовый еще пример #ifdef DEBUG printf("."); // Пусть каждый считатнный байт сопровождается точкой на консоли #endif

//--- "It is BINARY %d bytes written to COM-port:\n", 16); // Дошел до сюда и встал if ((lookfor(Readbuf, nread, sample1, samplesize1) == -1) && ((lookfor(Readbuf, nread, sample1, samplesize1) == -1)) { // не найдено } else { // Нашли! } /******************************************************************************************** Этот кусок кода тоже пока не трогал for (i = 0; i <= (BytesRead - 2); i++) // find bytes as correspondents to Garmin Messages { if ((bRead[i] == 0x10 && bRead[i + 1] == 0x36 && bRead[i + 2] == 0x0C) || (bRead[i] == 0x10 && bRead[i + 1] == 0x38 && bRead[i + 2] == 0x28)) { printf("Bytes readed %lu, found Garmin Message %d\n", BytesRead, (int)bRead[i+1]); break; } else { printf("Bytes readed %lu, NOT found Garmin Message, EXIT!\n", BytesRead); return; } }

// open port - Garmin feature! ////write(fd,GarminStop,8); usleep(1000); write(fd,GarminStart,8); n = fwrite(GarminStop, sizeof(char), 8, fp); usleep(1000); n = fwrite(GarminStart, sizeof(char), 8, fp); usleep(500000); // pause 0.5 sec before reading printf("\n%d Garmin commands is written!\n", 2); // read in cicle by Timer messages from Garmin while (!SIGINT || !VINTR) // if NOT signal = Ctrl+C Ctrl+Break { sleep (1); // in Sec, or maybe in microSec: usleep(1000000); // write to fdout-file, bytes readed, read to BUFSIZE bytes, read from COM-port if (!fread(fdout, BytesRead, BUFSIZE, fp)) perror("Read port: none bytes readed from /dev/ttyS0"); } ********************************************************************************************/ // Уходя не забываем сказать "до свидания!" и закрыть за собой двери. fclose(fdout); fclose(fd); exit(EXIT_SUCCESS); // Сакцесс он и в Африке сакцесс! }

А сейчас попробую прокомментировать Ваш предыдущий пост.

#184095
sklimkin написал:

Вы кстати тоже не представились.

Жевак Александр Антонович

sklimkin написал:
Меня порадовал размер исполняемого файла 7.5 кБ (проверил в CodeLite - то же самое).

Да. Меня этот факт тоже приводит в восторг. За графику приходится расплачиваться сотнями килобайт.

sklimkin написал:

В этом тесте мне не удалось использовать read() -- write() и fread() -- fwrite() в одной программе.
Но если в Винде это возможно, то в Линуксе тем более (думаю я пока).

Имеется две группы функций. (На самом деле их больше, но Вы затронули эти две.)

Первая группа имеет имена open, read, write, creat.
Вторая -- fopen, fread, fwrite, fclose.

Первая группа -- это вызовы системных функций. (Считайте, что функции находятся в ядре.)

Вторая -- это стандартные функции библиотеки С. Они буферированные. Поэтому на порциях не кратных размеру блока информации (кластеру) они работают быстрее, чем функции из первой группы. И в самом деле, при записи вы пересылаете свои данные не сразу на диск, а в буфер, т.е. в ОЗУ. И только когда в буфере окажется достаточно большое количество байт информации, вся информация одни большим куском "улетит" на диск. Оптовая поставка!

Поскольку обе функций группы выполняют по сути одни и те же действия с одними и теми же устройствами, то одновременно использовать в одной программе обе группы считается дурным тоном. Во всяком случае новичкам крайне не рекомендуется это делать. Можно наскочить на трудно объяснимые ошибки или еще какие-нибудь трудно постижимые побочные эффекты.

Я бы Вам рекомендовал работать со второй группой -- с группой функций стандартной библиотеки С, а не с первой. Это и быстрее, и субъективно проще.

sklimkin написал:

Первое беглое знакомство с man-ами и info-ми не порадовало, ну не MSDN это (хотя и в MSDN'е опухнешь искать нечто маленькое и редко надобное).

О-о! Это целая философия!
Для программирования в рамках POSIX не нужно много знать. Я имею ввиду следующее. Сравните, например, количество и тяжесть функций по открытию или созданию файла в Unix/Linux и аналогичных в Windows. Майкрософтовская CreateFile достойна ночных кошмаров! Чего только в нее они не напихали! Конечно, если так подходить к системе, предоставлять программеру таких монстров, то с помощью man-а помочь ему будет сложно. Наверно только с помощью MSDN-а, как-то удается помогать бедным программистам.

Вообще, это называется Unix-way. Это еще называется KISS -- "Keep It Simple, Stupid!" ("Делай это проще, придурок!") Самое забавное, что вот такие игры с монструозными функциями, вот такие "закидоны" с системами безопасности при доступе к файлам (SystemAttributes -- кто писал под Венду, знает) никак не спасают Виндовс от загрызающей ее вирусни. Программисты-вИндусы не там чинят свое дырявое ведро. Хотя, сказанное мною весьма холиварно, но доля истины там тоже есть. Надо не утяжелять функции разными параметрами. Чтобы исправить Венду, нужно менять в корне всю систему. В фундаменте Венды был изначально заложен кривой камень. И теперь как бы строители не пытались возводить стены вертикально, в итоге все равно у них получается Пизанская башня. А конечные юзеры - что? Они в двигатель (под капот) не лазают, и знать не знают, за что они платят свои деньги. Три раза "гы".

sklimkin написал:

а новый v. 10.x не устанавливается в моей Юбунте

Какая у Вас версия Убунты? Дело в том, что C::B 10.05 находится в уже готовом виде в репозиториях Убунты, начиная с версии 10.04. Инсталлируется на ура!

sklimkin написал:
Поскольку к рюшечкам у меня пиетета нет, то думаю для обычных окон-кнопок-боксов подойдет CodeLite или geany.
В любом случае придется переучиваться с Win-IDE на Lin-IDE.

А я что-то в последнее время вообще с катушек съехал. Сейчас не пользуюсь никакими IDE. Все делаю на дескопе -- три традиционных окна: окно псевдо-терминала, окно редактора (gedit) и окно Наутилуса. Управление проектом веду из Makefile-ла с помощью комады make <что-надо-сделать>.

Создаю из трех этих окон себе IDE следующим образом:

  • [*]открываю в наутилусе директорий с рабочим проектом,
  • нажимаю Ctrl-L -- верхний ряд кнопок с названиями поддиректориев превращается в строку, где прописан полный путь к этому директорию. Строка подсвечена -- значит, уже находится в первом буфере обмена. (Все знают, что в отличие от Венды, в Линуксе два буфера обмена?)
  • нажимаю Ctrl-Alt-T -- Открывается окно псевдо-терминала и становится текущим активным (имеющим фокус ввода) окном.
  • нажимаю кнопки "cd" и пробел,
  • щелкаю колеском мыши в окне (псевдотерминала) -- строка абсолютного пути из наутилуса попадает в командную строку терминала.
  • нажимаю Enter -- директорий с рабочим проектом становится текущим в окне терминала.
  • можно набрать команду make (всего четыре кнопочки -- это намного быстрее, чем прицельно щелкнуть мышкой. Не вру!)
sklimkin написал:

По поводу рута и усера в Линуксе внимательно Вас выслушаю. Пока не понимаю, зачем быть пользователем на своем домашнем компьютере, тем более что многие экзальтированные линуксоиды кричат о том что нет вирусных угроз в Линуксе - "это вам не то (Windows)".
Наверное я пока не вижу других проблем от такого пользования, ну и привычки от Win-XP.

Чуть позже. Слишком много нужно сказать. Просто не успеваю.

Исходный текст пока не смотрел. Не успеваю.

Войдите или зарегистрируйтесь, чтобы ответить.