Продолжаем развивать тему использования компьютера с ubuntu server в качестве устройства для связи мира микроконтроллеров с миром персональных компьютеров.
Ссылка на часть 1
Напомню, что статья описывает практику применения описанной техники и не ставит целью охватить все глубины и возможности современной аппаратуры. Это один из вариантов решения поставленной задачи.
В этой части я покажу, как проходить следующие моменты:
Друзья, жду Ваших интересных комментариев и ценных советов. Если где соврал — сильно не гневайтесь, просто указывайте, что можно сделать лучше. Надеюсь, появится 3 часть про большой скрипт, автоустановку… может ещё что.
Ссылка на часть 1
Напомню, что статья описывает практику применения описанной техники и не ставит целью охватить все глубины и возможности современной аппаратуры. Это один из вариантов решения поставленной задачи.
В этой части я покажу, как проходить следующие моменты:
Статический IP + DHCP сервер
В локальной сети на данный момент предполагается всего два устройства. Сам сервер и управляющая машина. Исходя из данной простоты настроим Ubuntu server.
Статический IP
Опорная информация
1. Чтобы узнать логическое имя (logical name) сетевого интерфейса делаем:
Вариант использования функции ifconfig (как аналог ipconfig в windows) иногда может дать только loop 127.0.0.1. Название интерфейса зависит от аппаратуры. На двух разных машинах ставил ubuntu с одной флэшки и были разные имена сетевых интерфейсов. enp3s0 — это классификация по шине и номеру устройства, как я понимаю. Бывают ещё из такой серии eth0 и такой ens35. Не пугайтесь.
2. Изменение файла конфигурации сети
Должно быть так:
Нажимаем cntrl-x — для выхода из редактора
Нажимаем y — для сохранения изменений
3. Перезагружаем сетевой сервис:
DHCP сервер
Опорная информация
1. Редактируем файлы для работы DHCP сервера
В файле
2. Если будете использовать функцию gethostbyname(), то в файле
В файле /etc/hostname хранится имя пк (ubuntu). Можно посмотреть через
3. Перезагружаем сетевой сервис:
SSH доступ
По идее, подключив теперь стационарный компьютер, мы получи для него IP и сможем иметь доступ по SSH. Для доступа из Windows я использовал утилиту PuTTY. Там же, в программных файлах PuTTY, есть утилита для передачи данных по сети.
Вот состав батника для передачи файлов с Ubuntu на Windows.
И для закачки на сервер
Статический IP
Опорная информация
1. Чтобы узнать логическое имя (logical name) сетевого интерфейса делаем:
sudo lshw -C network
и ищем строчку logical name: enp3s0
Вариант использования функции ifconfig (как аналог ipconfig в windows) иногда может дать только loop 127.0.0.1. Название интерфейса зависит от аппаратуры. На двух разных машинах ставил ubuntu с одной флэшки и были разные имена сетевых интерфейсов. enp3s0 — это классификация по шине и номеру устройства, как я понимаю. Бывают ещё из такой серии eth0 и такой ens35. Не пугайтесь.
2. Изменение файла конфигурации сети
sudo nano /etc/network/interfaces
(nano — эта маленький текстовый редактор)Должно быть так:
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).
source /etc/network/interfaces.d/*
# The loopback network interface
auto lo
iface lo inet loopback
# My local network.
allow-hotplug enp3s0
iface enp3s0 inet static
address 172.16.55.1
netmask 255.255.255.0
gateway 172.16.55.1
Нажимаем cntrl-x — для выхода из редактора
Нажимаем y — для сохранения изменений
3. Перезагружаем сетевой сервис:
service networking restart
DHCP сервер
Опорная информация
1. Редактируем файлы для работы DHCP сервера
sudo nano /etc/default/isc-dhcp-server
найдите строчку INTERFACES=""
— это название интерфейса для DHCP сервера. В нашем случае должно быть так:INTERFACES="enp3s0"
В файле
sudo nano /etc/dhcp/dhcpd.conf
нужно добавитьsubnet 172.16.55.0 netmask 255.255.255.0{
range 172.16.55.2 172.16.55.100;
}
В рамках этой подсети DHCP сервер будет выдавать адреса в диапазоне от 2 до 100.2. Если будете использовать функцию gethostbyname(), то в файле
sudo nano /etc/hosts
должно быть прописано имя пк и IP. Возможно есть более удобный способ получить свой собственный IP, но мне он не поддался.127.0.0.1 localhost
172.16.55.1 ubuntu
В файле /etc/hostname хранится имя пк (ubuntu). Можно посмотреть через
sudo cat /etc/hostname
и ещё миллионом способов.3. Перезагружаем сетевой сервис:
service networking restart
SSH доступ
По идее, подключив теперь стационарный компьютер, мы получи для него IP и сможем иметь доступ по SSH. Для доступа из Windows я использовал утилиту PuTTY. Там же, в программных файлах PuTTY, есть утилита для передачи данных по сети.
Вот состав батника для передачи файлов с Ubuntu на Windows.
d:\"Program Files"\PuTTY\pscp.exe ubuntu@172.16.55.1:/home/ubuntu/tool/* "F:/WORK/SERVER/tool/"
И для закачки на сервер
d:\"Program Files"\PuTTY\pscp.exe "F:/WORK/SERVER/tool/*" ubuntu@172.16.55.1:/home/ubuntu/tool/
Ставим драйвер от FTDI
Драйвера от FTDI поставляются в сжатом виде. Содержатся в пакете сами драйвера, библиотеки, примеры использования и README.pdf файл, который больше всего был интересен. Из файла D3XX Programmers Guide ни разу не ясно, как использовать драйвер для Linux. Пришлось даже написать в тех поддержку FTDI, благо они своевременно и по делу отвечают. Можно было бы и не писать, если бы я сразу раскрыл этот архив. Но полезными оказались ссылки, которые они прислали, примеры разводки и схемотехники.
Как показано выше, с помощью утилиты pscp из комплекта PuTTY, копируем на сервер драйвер. У меня был d3xx-linux-i686-0.5.0.tar.bz2. Заходим в эту папку на сервере и делаем
Далее, по инструкции FTDI исполняем:
Как показано выше, с помощью утилиты pscp из комплекта PuTTY, копируем на сервер драйвер. У меня был d3xx-linux-i686-0.5.0.tar.bz2. Заходим в эту папку на сервере и делаем
tar -xvf d3xx-linux-i686-0.5.0.tar.bz2
Далее, по инструкции FTDI исполняем:
cd linux-i686
sudo rm -f /usr/lib/libftd3xx.so
sudo cp -f libftd3xx.so /usr/lib
sudo cp -f libftd3xx.so.0.5.0 /usr/lib
sudo cp -f 51-ftd3xx.rules /etc/udev/rules.d
sudo udevadm control --reload-rules
Компилируем программу
Программу я писал в codeBlocks и она, за исключением некоторых моментов, в том числе и из-за FTDI, совместима с Windows. Перестала она компилироваться для Windows, когда я поставил туда h файл из драйвера для linux D3XX (c D2XX и FT232RL чипом не было проблем).
Теперь makefile. Программисты и так знают зачем он нужен, просто укажу особенности:
STATLIB=libftd3xx.a — указываем название библиотеки для Linux
CFLAGS=$(DEPENDENCIES) -Wall -Wextra -std=c++11 — разрешаем c++11
Таким образом, в папке проекта лежат файлы main.c ftd3xx.h makefile libftd3xx.a и прочие файлы проекта. И для компиляции проекта теперь нужно зайти в эту папку и сделать
Теперь makefile. Программисты и так знают зачем он нужен, просто укажу особенности:
STATLIB=libftd3xx.a — указываем название библиотеки для Linux
CFLAGS=$(DEPENDENCIES) -Wall -Wextra -std=c++11 — разрешаем c++11
пример makefile для одного файла проекта main.cpp
CC=g++
UNAME := $(shell uname)
ifeq ($(UNAME), Darwin)
DEPENDENCIES := -lpthread -ldl -lobjc -framework IOKit -framework CoreFoundation
else
DEPENDENCIES := -lpthread -ldl -lrt
endif
CFLAGS=$(DEPENDENCIES) -Wall -Wextra -std=c++11
STATLIB=libftd3xx.a
APP = prgr
all: $(APP)
$(APP): main.o
$(CC) -o $(APP) main.o $(STATLIB) $(CFLAGS)
main.o: main.cpp
$(CC) -c -o main.o main.cpp $(CFLAGS)
clean:
rm -f *.o ; rm $(APP)
Таким образом, в папке проекта лежат файлы main.c ftd3xx.h makefile libftd3xx.a и прочие файлы проекта. И для компиляции проекта теперь нужно зайти в эту папку и сделать
make
daemon
Роль демонов в Linux похожа на роль служб в Windows. Это программы, которые живут в фоновом режиме и делают всякую периферическую работу. Всё начинается с systemd — программы, которая запускается первой, имеет соответственно PID=1, и запускает все другие фоновые задачи через скрипты. Поковырявшись в Ubuntu, я удивился насколько много всего внутри построено на скриптах. Вы уже видели, как меняется статический IP, настраиваются программы, простой коррекцией файлов в текстовом редакторе.
Выполнив
Так вот, при запуске демона исполняется скрипт, в котором указано когда и как программу нужно запустить, как её остановить или перезапустить. Чтобы демон работал нормально, программа при запуске должна сохранить в файл, путь к которому указан в скрипте, свой PID и перейти в другой поток (в фоновый режим).
Пособие по демону меня ввело в грусть и тоску. Сильно упростив демона, я его превратил в утилиту для запуска любой программы. Но обязательная часть не поменялась. Помимо этого, он ведет лог, чтобы проверить, если вдруг что.
Компилируем демона.
На данный момент в нашем рабочем каталоге, допустим /home/ubuntu/daemon/, имеем:
daemon — программа демона
prgr — программа
prgr.strt — скрипт, который нужно выполнить до запуска программы (если надо)
prgr.stop — скрипт, который нужно выполнить для остановки программы (если надо)
Нужно разрешить программам работать:
Теперь нужен скрипт для systemd
Делаем
В скрипте кратко:
Description — краткое название-описание
After — что требуется для запуска
Type=forking — systemd предполагает, что служба запускается однократно и процесс разветвляется с завершением родительского процесса.
PIDFile — файл с PID программы из демона
ExecStartPre — до запуска программы
ExecStart — программа с параметрами
ExecStop — как остановить
WantedBy — уровень, на котором запускать
Теперь можно попробовать всё запустить.
Пишем
Если всё без ошибок, то запускаем:
После этого смотрите лог демона, всё должно поехать.
Чтобы работала автозагрузка
Выполнив
ps -el
Вы увидите список запущенных программ с их PID. PID — это обязательный идентификатор запущенной программы, по которому за этой программой следит ОС. В крайней ситуации, можно грохнуть программу по этому PID из терминала — пишите kill и PID (может пригодиться для отладки).Так вот, при запуске демона исполняется скрипт, в котором указано когда и как программу нужно запустить, как её остановить или перезапустить. Чтобы демон работал нормально, программа при запуске должна сохранить в файл, путь к которому указан в скрипте, свой PID и перейти в другой поток (в фоновый режим).
Пособие по демону меня ввело в грусть и тоску. Сильно упростив демона, я его превратил в утилиту для запуска любой программы. Но обязательная часть не поменялась. Помимо этого, он ведет лог, чтобы проверить, если вдруг что.
код daemon
void SetPidFile(char* Filename)
{
FILE* f;
f = fopen(Filename, "w+");
if (f)
{
fprintf(f, "%u", getpid());
fclose(f);
}
}
int main( int argc, char** argv )
{
char toolfile[32];
char folder[32];
intptr_t ret;
FILE* logfile;
if( argc!=3 )
{
printf( "Write address of the program and name: /home/ubuntu/tool/ tool\n");
return -1;
}
pid_t pid, sid;
pid = fork();
if (pid < 0)
{
sleep(1);
return -1;
}
//We got a good pid, Close the Parent Process
if (pid > 0) {
return 0;
}
//Create a new Signature Id for our child
sid = setsid();
if (sid < 0)
{
return -1;
}
//Change File Mask
umask(0);
//Save PID
memcpy( toolfile, argv[0], strlen(argv[0]) );
memcpy( toolfile + strlen(argv[0]), ".log", 4 );
memset( toolfile + strlen(argv[0]) + 4, 0, 1 );
printf( "Daemon:: log to:%s\n", toolfile );
logfile = fopen( toolfile, "w" );
fprintf( logfile, "Daemon:: started with 0=%s 1=%s 2=%s\n", argv[0], argv[1], argv[2] );
memset( toolfile, 0, 32 );
memcpy( toolfile, argv[0], strlen(argv[0]) );
memcpy( toolfile + strlen(argv[0]), ".pid", 4 );
memset( toolfile + strlen(argv[0]) + 4, 0, 1 );
SetPidFile( toolfile );
fprintf( logfile, "Daemon:: PID=%u saved in the %s\n", getpid(), toolfile );
memset( folder, 0, 32 );
memcpy( folder, argv[1], strlen(argv[1]) );
fflush ( logfile );
memset( toolfile, 0, 32 );
memcpy( toolfile, folder, strlen(argv[1]) );
memset( toolfile + strlen(argv[1]), '/', 1 );
memcpy( toolfile + strlen(argv[1]) + 1, argv[2], strlen(argv[2]) );
//Change Directory
//If we cant find the directory we exit with failure.
if ((chdir(folder)) < 0)
{
fprintf( logfile, "Daemon:: Program folder was not found:%s\n", folder );
fclose( logfile );
return -1;
}
//Close Standard File Descriptors
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
fprintf( logfile, "Daemon:: Program started\n" );
fflush ( logfile );
ret = execl( toolfile, folder, NULL );
if( ret==-1 )
{
fprintf( logfile, "Daemon:: execl error: %s. File=%s Folder=%s\n", strerror(errno), toolfile, folder );
fclose( logfile );
return -1;
}
fprintf( logfile, "Daemon:: closed\n" );
fclose( logfile );
return 0;
}
Компилируем демона.
На данный момент в нашем рабочем каталоге, допустим /home/ubuntu/daemon/, имеем:
daemon — программа демона
prgr — программа
prgr.strt — скрипт, который нужно выполнить до запуска программы (если надо)
prgr.stop — скрипт, который нужно выполнить для остановки программы (если надо)
Нужно разрешить программам работать:
sudo chmod 755 ./tool
sudo chmod 755 ./daemon
Теперь нужен скрипт для systemd
Делаем
sudo nano /etc/systemd/system/mydaemon.service
и записываем туда наш скрипт.mydaemon.service
[Unit]
Description=my service
After=network.target
After=isc-dhcp-server.service
[Service]
Type=forking
PIDFile=/home/ubuntu/daemon/daemon.pid
ExecStartPre=/bin/sh /home/ubuntu/daemon/prgr.strt
ExecStart=/home/ubuntu/daemon/daemon /home/ubuntu/daemon/prgr prgr
ExecStop=/bin/sh /home/ubuntu/daemon/prgr.stop
Restart=always
TimeoutSec=5
[Install]
WantedBy=multi-user.target
В скрипте кратко:
Description — краткое название-описание
After — что требуется для запуска
Type=forking — systemd предполагает, что служба запускается однократно и процесс разветвляется с завершением родительского процесса.
PIDFile — файл с PID программы из демона
ExecStartPre — до запуска программы
ExecStart — программа с параметрами
ExecStop — как остановить
WantedBy — уровень, на котором запускать
Теперь можно попробовать всё запустить.
Пишем
systemctl daemon-reload
systemctl status mydaemon
Если всё без ошибок, то запускаем:
systemctl start mydaemon
После этого смотрите лог демона, всё должно поехать.
Чтобы работала автозагрузка
systemctl enable mydaemon
Друзья, жду Ваших интересных комментариев и ценных советов. Если где соврал — сильно не гневайтесь, просто указывайте, что можно сделать лучше. Надеюсь, появится 3 часть про большой скрипт, автоустановку… может ещё что.