UDP - TCP - Arduino
ArduNetstD — программа для обмена данными с ардуиной и другими девайсами.
Началось всё с того, что была написана программа для удалённого управления ардуиной по протоколу UDP…
… следом появилась идея сделать программу (по типу ser2net), способную гонять данные туда-сюда используя разные протоколы.
В итоге получился прокси-сервер ardunetstd, который умеет вот что…
• Работает по протоколам UDP и TCP.
• Перегоняет данные «как есть» в ардуину и обратно.
• Предоставляет WEB-интерфейс для управления ардуиной.
• Даёт возможность обмениваться данными с ардуиной при помощи программ типа curl.
• Размер файла 8кБ (при работе на роутере флешка не требуется).
Подключать можно не только ардуину, но и другие USB-устройства, например, я подключал GPS-приёмник BU-353.
Никаких сторонних программ для настройки порта не нужно.
Как пользовать
Скачать ardunetstd
Для компьютера x64
Для Atheros (MR3020)
Для Broadcom (Asus wl-500)
Если нужно для иного роутера, тогда пишите в комментах.
Запускается программа с параметрами, которые отвечают за режим работы:
./ardunetstd /dev/ttyUSB0 57600 /tmp/tmp.txt 3495 3496 "192.168.1.224" 0 0 8080 /opt/index.web 1 100000
Двенадцать параметров разделённых пробелом.
1. Путь до ардуины.
2. Скорость порта (9600, 19200, 38400, 57600, 115200).
3. Файл в который записываются данные принятые от ардуины, он будет создаваться сам при каждом запуске программы, называться может как угодно. Находиться тоже может где угодно, однако лучше использовать папку /tmp (это временная папка, которую создаёт система в оперативной памяти).
4. Порт для upd-сервера (на этот порт приходят данные от клиента), можно указать какой-либо другой.
5. Порт для upd-клиента (на этот порт ardunetstd будет отправлять клиенту данные от ардуины), можно указать какой-либо другой.
6. Адрес udp-клиета, которому будут отправляться данные принятые от ардуины (писать в кавычках — «192.168.1.224»).
7. Запуск udp-сервера (0 — не запускать, 1 — запускать).
8. Запуск udp-клиента (0 — не запускать, 1 — запускать).
9. Порт для web-сервера.
10. Путь к файлу index.web
11. Запуск web-сервера (0 — не запускать, 1 — запускать).
12. Пауза перед отправкой ответа на web-страничку (в микросекундах).
Для остановки программы нажмите
killall -s 9 ardunetstd
Теперь подробнее обо всём…
WEB
Начну с конца, точнее с web-сервера. Предположим Вы хотите поуправлять ардуиной (подключённой к роутеру или обычному компьютеру) или просто передать её что-то через веб-страничку. Для этого нужно положить ardunetstd в любую папку, допустим в /opt…
Создайте папку, загрузите ardunetstd и дайте права:
mkdir /opt
cd /opt
wget ...
chmod -R 777 /opt
Далее надо в той же папке создать файл с html-кодом, который ardunetstd будет отдавать клиенту. Это такой же index.html-файл (как и в обычных серверах), только назвать его можно как угодно, у меня он будет называться index.web.
Создайте в папке /opt файл index.web с таким содержимым:
Если создавать влом, то можно его скачать...
cd /opt
wget //istarik.ru/file/index.web
<!DOCTYPE html><html><head>
<title>ArduNet stD</title>
<style>
body { background-color: #353535; color: #999; }
h1 { font-size: 60px; text-align: center; color: #353535; text-shadow: 0 0 2mm #ed9399}
</style></head>
<body><h1>ArduNet stD</h1>
<form action='' method='GET'>
<input type='text' name='To_Ardu' placeholder='To Ardu' size='50'>
<input id='submit' type='submit' value='Отправить'>
</form>
Получил от Ардуины:
</body></html>
Заливаем в ардуину код:
void setup()
{
Serial.begin(57600);
pinMode(13, OUTPUT);
pinMode(12, OUTPUT);
}
void loop()
{
char from_server;
while(Serial.available())
{
delay(1);
from_server = Serial.read();
// D13
if(from_server == 'A')
{
digitalWrite(13, HIGH);
Serial.print("D13 VKL");
Serial.print('\n'); // это всегда должно быть везде
}
if(from_server == 'a')
{
digitalWrite(13, LOW);
Serial.print("D13 OTKL");
Serial.print('\n');
}
// D12
if(from_server == 'B')
{
digitalWrite(12, HIGH);
Serial.print("D12 VKL");
Serial.print('\n');
}
if(from_server == 'b')
{
digitalWrite(12, LOW);
Serial.print("D12 OTKL");
Serial.print('\n');
}
} // конец while
} // конец loop
Ардуина будет получать символ, выполнять действие и отправлять обратно статус. То есть отправляет данные только по запросу.
Далее предполагается, что ваша ардуина определилась как /dev/ttyUSB0
Проверить можно так:
ls /dev/tty*
Если действия происходят на «большом компьютере», тогда стартуйте ardunetstd через sudo
sudo /opt/ardunetstd ...
Запускаем ardunetstd
Сделайте файл исполняемым.
sudo chmod +x /opt/ardunetstd
/opt/ardunetstd /dev/ttyUSB0 57600 /tmp/tmp.txt 3495 3496 "192.168.1.224" 0 0 8080 /opt/index.web 1 100000
В данном случае web-сервер запущен «1» на порту «8080», udp-сервер и udp-клиент отключены «0» «0».
Перейдя в браузере по адресу — адрес:8080, увидите картинку:
Впишите в поле символ А и нажмите «Отправить», на ардуине загорится D13 и появится ответ «D13 VKL».
В терминал будут выведены сообщения о проделанных действиях:
OK_GET — получен GET-запрос.
GET_send_toArdu: echo 'A' > /dev/ttyUSB0 — пришедший с GET-запросом символ 'A' отправлен ардуине.
Str_NOT_equally — об этом ниже.
Reciv_from_arduino: D13 VKL | Bytes — 8 — от ардуины получена строка 'D13 VKL' размером 8 байт (восьмой байт это — \n).
Send to web_client: D13 VKL — клиенту отправлено 'D13 VKL'.
Как это работает?
Когда Вы открываете страничку, ardunetstd читает из файла index.web html-код и отдаёт его браузеру.
Когда отправляете символ, ardunetstd перенаправляет его в ардуину и становится на паузу в ожидании ответа.
Если данные принятые от ардуины не отличаются от тех, что содержатся в /tmp/tmp.txt, тогда их перезапись не производится (в терминале будет сообщение Str_equally), в противном случае данные перезапишутся, а терминал сообщит — Str_NOT_equally. Ниже будет объяснено назначение временного файла.
Curl — как пользоваться.
Откройте второй терминал и дайте команду:
curl localhost:8080/A
Вместо localhost впишите свой адрес.
Загорится D13 и во втором терминале будет выведена принятая от ардуины строка:
В первом терминале будут сообщения о проделанных действиях:
Если сделать пустой запрос:
curl localhost:8080
Тогда в ардуину отправится пустая строка и она ничего не ответит. Клиенту будет отправлена информация хранящаяся во временном файле /tmp/tmp.txt
WARNING!
Если планируется передача большого объёма данных, то нужно помнить о том, что у ардуины выделены довольно-таки скромные входящий (RX) и исходящий (TX) буферы, посмотреть и изменить их можно в файле /arduino-x.x.x/hardware/arduino/avr/cores/arduino/HardwareSerial.h
В данном случае для буферов выделено по 64 байта (16 байт — это для МК с объёмом RAM меньше 1кБ), то есть, если передать в ардуину больше 64-ёх символов и не успеть их прочитать, то они просто потеряются. Чтобы избежать потери, нужно увеличить буфер до нужного значения, например, если вы передаёте ардуине 100 символов, то буфер должен быть 102 байта.
Однако помните о том, что увеличивая буфер, вы увеличиваете объём занятой оперативной памяти.
...
#if !defined(SERIAL_TX_BUFFER_SIZE)
#if (RAMEND < 1000)
#define SERIAL_TX_BUFFER_SIZE 16
#else
#define SERIAL_TX_BUFFER_SIZE 64
#endif
#endif
#if !defined(SERIAL_RX_BUFFER_SIZE)
#if (RAMEND < 1000)
#define SERIAL_RX_BUFFER_SIZE 16
#else
#define SERIAL_RX_BUFFER_SIZE 64
...
В данном случае для буферов выделено по 64 байта (16 байт — это для МК с объёмом RAM меньше 1кБ), то есть, если передать в ардуину больше 64-ёх символов и не успеть их прочитать, то они просто потеряются. Чтобы избежать потери, нужно увеличить буфер до нужного значения, например, если вы передаёте ардуине 100 символов, то буфер должен быть 102 байта.
Однако помните о том, что увеличивая буфер, вы увеличиваете объём занятой оперативной памяти.
Теперь изменим скетч таким образом, чтоб ардуина отправляла данные не по запросу, а делала это сама, с периодичностью в 250мс.
Предположим что Вы подключили к ардуине датчик температуры и хотите узнавать эту температуру не обращаясь к ардуине. То есть ардуина будет сама отправлять данные на сервер (ardunetstd), а сервер будет сохранять полученную инфу в файл /tmp/tmp.txt. Клиент, обращаясь к серверу будет забирать актуальные данные из /tmp/tmp.txt.
byte d13 = 0;
byte d12 = 0;
#define MAXMILLIS 4294967295
unsigned long timeobnv;
unsigned long timelapsed = 0;
int t = 22;
void setup()
{
Serial.begin(57600);
pinMode(13, OUTPUT);
pinMode(12, OUTPUT);
}
void loop()
{
char from_server;
while(Serial.available())
{
delay(1);
from_server = Serial.read();
// D13
if(from_server == 'A')
{
digitalWrite(13, HIGH);
d13 = 1;
}
if(from_server == 'a')
{
digitalWrite(13, LOW);
d13 = 0;
}
// D12
if(from_server == 'B')
{
digitalWrite(12, HIGH);
d12 = 1;
}
if(from_server == 'b')
{
digitalWrite(12, LOW);
d12 = 0;
}
} // конец while
unsigned long currtime = millis();
if(currtime > timeobnv) timelapsed = (currtime - timeobnv);
else timelapsed = (MAXMILLIS - timeobnv + currtime);
if(timelapsed >= 250)
{
timeobnv = currtime;
sendate();
}
} // конец loop
void sendate() // отправка данных
{
Serial.print("D13: ");
Serial.print(d13);
Serial.print(" D12: ");
Serial.print(d12);
Serial.print(" TEMP: ");
Serial.print(t);
Serial.print('\n'); // это всегда должно быть
}
К прежнему функционалу добавлены счётчик времени и переменная с температурой.
Если D12 и D13 включены, то отсылает единички, наоборот, нолики.
Запустите ardunetstd изменив длительность паузы (последний параметр) до 350000 мкс. Пауза увеличена для того, чтоб в случае отправки ардуине команды, ardunetstd дождался ответа (у него в запасе будет 100мс).
/opt/ardunetstd /dev/ttyUSB0 57600 /tmp/tmp.txt 3495 3496 "192.168.1.224" 0 0 8080 /opt/index.web 1 350000
В терминале побегут строки:
Отправьте из веб-интерфейса (или curl`ом) символ A, D13 загорится и инфа изменится.
Замечу, если открыть соседний терминал и посмотреть потребляемые ресурсы (top), то будет видно, что ardunetstd берёт на себя не больше 2% CPU.
С web-сервером всё, перейдём к udp…
UDP
Потребуется UDP-клиент/сервер. Здесь (istarik.ru/file/ihome.apk) можно скачать простейшую программу для Android с интерфейсом и функциями схожими с web-интерфейсом описанным выше.
Позже выйдет статья с описанием более симпатичного и функционального приложения.
Нужно указать ip-адрес устройства, на котором работает ardunetstd и порты, после чего нажать кнопку «сохранить» и перезапустить приложение:
Теперь остановите ardunetstd (Ctrl + c), верните в ардуину первый скетч из статьи, и запустите ardunetstd с параметрами включающими приём и отправку udp-пакетов:
/opt/ardunetstd /dev/ttyUSB0 57600 /tmp/tmp.txt 3495 3496 "192.168.1.224" 1 1 8080 /opt/index.web 1 350000
Нужно указать ip-адрес вашего смартфона.
Если в последнем разряде ip-адреса указать цифру 255 (192.168.1.255), то пакеты будут отправляться всем udp-клиентам локальной сети (broadcast).
Android-приложение будет отправлять и принимать пакеты на порты 3495 и 3496.
Пауза, в работе udp ни на что не влияет.
На смартфоне введите символ A и нажмите отправить:
Сверху появится сообщение от ардуины.
Терминал расскажет о проделанной работе:
UDP_reciv — принят udp-пакет.
UDP_send_to_ardu: A — пришедший символ 'A' отправлен ардуине.
Str_NOT_equally — файл tmp.txt обновлён.
Reciv_from_arduino: D13 VKL | Bytes — 8 — от ардуины получена строка 'D13 VKL' размером 8 байт.
UDP_send: D13 VKL — клиенту отправлено 'D13 VKL'.
Если отправить через веб или с помощью curl символ a, то информация изменится на всех клиентах.
Если веб-сервер не нужен, то отключите его, поменяв предпоследний параметр с 1 на 0.
/opt/ardunetstd /dev/ttyUSB0 57600 /tmp/tmp.txt 3495 3496 "192.168.1.224" 1 1 8080 /opt/index.web 0 350000
Теперь остановите ardunetstd и вновь залейте в ардуину скетч, который сам отправляет данные.
Запустите ardunetstd с отключёнными web и udp серверами:
/opt/ardunetstd /dev/ttyUSB0 57600 /tmp/tmp.txt 3495 3496 "192.168.1.224" 0 1 8080 /opt/index.web 0 350000
В терминале побегут строки, а на смартфоне всегда будет отображаться актуальная информация.
Если нужно только отправлять ардуине информацию, тогда можно наоборот, отключить udp-клиент и включить udp-сервер:
/opt/ardunetstd /dev/ttyUSB0 57600 /tmp/tmp.txt 3495 3496 "192.168.1.224" 1 0 8080 /opt/index.web 0 350000
В общем можно комбинировать работу ardunetstd как угодно, в зависимости от потребностей.
Совместная работа
Ardunetstd можно использовать совместно с другим сервером (uhttpd, lighttpd и т.д.).
Предположим у вас есть красивый сайт (работающий не важно на каком движке, писаный не важно на каком языке и получающий контент не важно от какого сервера) и вы хотите с помощью этого сайта управлять своим «умным домом».
Чтобы реализовать эту идею достаточно в ваш html-код добавить ajax-запрос, который будет через ardunetstd посылать команды ардуине и забирать ответ из файла tmp.txt. Ниже представлен пример.
Загрузите скетч:
byte d13 = 0;
byte d12 = 0;
#define MAXMILLIS 4294967295
unsigned long timeobnv;
unsigned long timelapsed = 0;
int t = 22;
void setup()
{
Serial.begin(57600);
pinMode(13, OUTPUT);
pinMode(12, OUTPUT);
}
void loop()
{
char from_server;
while(Serial.available())
{
delay(1);
from_server = Serial.read();
// D13
if(from_server == 'A')
{
digitalWrite(13, HIGH);
d13 = 1;
}
if(from_server == 'a')
{
digitalWrite(13, LOW);
d13 = 0;
}
// D12
if(from_server == 'B')
{
digitalWrite(12, HIGH);
d12 = 1;
}
if(from_server == 'b')
{
digitalWrite(12, LOW);
d12 = 0;
}
} // конец while
unsigned long currtime = millis();
if(currtime > timeobnv) timelapsed = (currtime - timeobnv);
else timelapsed = (MAXMILLIS - timeobnv + currtime);
if(timelapsed >= 250)
{
timeobnv = currtime;
sendate();
}
} // конец loop
void sendate() // отправка данных
{
Serial.print(d13);
Serial.print(" ");
Serial.print(d12);
Serial.print(" ");
Serial.print(t);
Serial.print('\n');
}
Ардуина будет отправлять ответ в виде строки 0 0 22, а в браузере он будет раскладываться по переменным.
Допустим вы всё делаете на роутере с установленным сервером uhttpd (установить можно так opkg install uhttpd). Тогда скачайте архив и распакуйте его в папку /www, получится так /www/ajax.
Запустите ardunetstd указав путь для файла tmp.txt так, чтоб он создавался в папке с сайтом:
/opt/ardunetstd /dev/ttyUSB0 57600 /www/ajax/tmp.txt 3495 3496 "192.168.1.224" 1 1 8080 /opt/index.web 1 350000
В файле index.html (из архива) впишите адрес роутера:
...
<script>
var dlina = 3;
var stroka;
var adres = 'http://192.168.5.197:8080/='; # поменять нужно только ip-адрес
...
Открыв в браузере — адрес/ajax/, увидите следующую картинку…
Нажмите кнопку D13 и надпись станет ярче, на ардуине загорится светодиод, в терминале появятся знакомые сообщения, а на смартфоне нолик сменится на единичку.
Пошлите со смартфона символ a и кнопка D13 потускнеет.
То же самое на пхп — fopen(“/tmp/tmp.txt”,”r”) и т.д...
GPS
Как писалось выше, подключать можно не только ардуину. Если подключить gps-приёмник BU-353 и запустить ardunetstd указав скорость 4800…
/opt/ardunetstd /dev/ttyUSB0 4800 /tmp/tmp.txt 3495 3496 "192.168.1.224" 1 1 8080 /opt/index.web 1 350000
… то в терминал посыплются данные.
При желании можно подключить несколько девайсов, запустив несколько программ, только нужно указывать другие порты.
В итоге получился универсальный комбайн для взаимодействия с usb-девайсами.
На этом пожалуй всё, если что-то не понятно, спрашивайте в комментах.
Исходники
Android
ardunetstd
ardunetstd
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/wait.h>
#define BUFSIZE 2048
char response[] = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n";
char index_file[BUFSIZE]={0,};
char index_filepatch[128]={0,};
char bRead[BUFSIZE] = {0,};
char device[32]={0,};
char file_ardu_patch[128]={0,};
char str_iz_file[BUFSIZE] = {0,};
char adr_udp[24] = {0,};
unsigned long int speedport = 0;
unsigned int PORTR = 0;
unsigned int PORTS = 0;
int udp_s = 0;
int udp_c = 0;
unsigned int PORTW = 0;
int web = 0;
unsigned long int PAUSARD = 0;
int fd;
struct sockaddr_in server;
struct hostent *host;
int sockfd;
pid_t udp_server;
pid_t web_server;
pid_t web_server2;
void error_log(char *err)
{
time_t t;
time(&t);
FILE *f;
f = fopen("Error.log", "a");
fprintf(f, "%s. ", err);
fprintf(f, "%s", ctime( &t));
printf("Write to Error.log\n");
fclose(f);
kill(udp_server, SIGTERM);
kill(web_server, SIGTERM);
kill(web_server2, SIGTERM);
exit(0);
}
void read_index_file()
{
char result_sting[BUFSIZE];
FILE *file;
file = fopen(index_filepatch,"r");
if(file == NULL)
{
error_log("Error-Open index_file");
}
while(fgets(result_sting,sizeof(result_sting),file))
{
strcat(index_file, result_sting);
}
fclose(file);
}
void open_port()
{
fd = open(device, O_RDWR | O_NOCTTY);
if(fd == -1)
{
error_log("Error - NOT open port");
}
else
{
struct termios options;
tcgetattr(fd, &options);
switch(speedport)
{
case 4800:
cfsetispeed(&options, B4800);
cfsetospeed(&options, B4800);
break;
case 9600:
cfsetispeed(&options, B9600);
cfsetospeed(&options, B9600);
break;
case 19200:
cfsetispeed(&options, B19200);
cfsetospeed(&options, B19200);
break;
case 38400:
cfsetispeed(&options, B38400);
cfsetospeed(&options, B38400);
break;
case 57600:
cfsetispeed(&options, B57600);
cfsetospeed(&options, B57600);
break;
case 115200:
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
break;
default:
printf("Error - Speed_port\n");
error_log("Error - Speed_port");
break;
}
options.c_cflag |= (CLOCAL | CREAD);
options.c_iflag = IGNCR;
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
options.c_cc[VMIN] = 1;
options.c_cc[VTIME] = 1;
options.c_lflag = ICANON;
options.c_oflag = 0;
options.c_oflag &= ~OPOST;
tcflush(fd, TCIFLUSH);
tcsetattr(fd, TCSANOW, &options);
}
}
int main(int argc, char *argv[])
{
if(argc != 13)
{
printf("Not argumets!\n");
error_log("Not argumets");
}
strncpy(device, argv[1], 31); // arduina
speedport = strtoul(argv[2], NULL, 0); // baud rate
strncpy(file_ardu_patch, argv[3], 127); // путь к файлу ardu
PORTR = strtoul(argv[4], NULL, 0); // порт для upd-сервера 3495 (приём)
PORTS = strtoul(argv[5], NULL, 0); // порт для upd-клиента 3496 (отправка)
strncpy(adr_udp, argv[6], 23); // адрес udp-сервера для отправки
adr_udp[sizeof(adr_udp) - 1] = 0;
udp_s = atoi(argv[7]); // запуск udp-сервера ( 0 - не запускать, 1 - запускать)
udp_c = atoi(argv[8]); // запуск udp-клиента ( 0 - не запускать, 1 - запускать)
PORTW = strtoul(argv[9], NULL, 0); // порт для web-сервера 8080
strncpy(index_filepatch, argv[10], 127); // путь к файлу index.html
web = atoi(argv[11]); // запуск web-сервера ( 0 - не запускать, 1 - запускать)
PAUSARD = strtoul(argv[12], NULL, 0); // пауза перед приёмом
FILE *f;
f = fopen(file_ardu_patch, "w");
if(f == NULL)
{
error_log("Error-Create file");
}
fclose(f);
open_port();
sleep(2);
tcflush(fd, TCIFLUSH);
////////////////////////////////// udp_server //////////////////////////////////////////
if(udp_s)
{
udp_server = fork();
if(-1 == udp_server)
{
error_log("Not udp_PID");
}
if(udp_server == 0)
{
char msg[BUFSIZE] = {0,};
char to_Ardu[BUFSIZE] = {0,};
memset(&server, 0x00, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons(PORTR);
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
error_log("Not sockfd udp_server");
}
if (bind(sockfd, (struct sockaddr *) &server, sizeof(server)))
{
error_log("Not bind udp_server");
}
while(1)
{
memset(msg, 0, sizeof(msg));
memset(to_Ardu, 0, sizeof(to_Ardu));
int n = recvfrom(sockfd, msg, BUFSIZE - 1, 0, NULL, NULL);
msg[n] = 0;
printf("UDP_reciv\n");
snprintf(to_Ardu, BUFSIZE - 1, "echo '%s' > %s", msg, device);
system(to_Ardu);
printf("UDP_send_to_ardu: %s\n", msg);
}
close(sockfd);
return EXIT_SUCCESS;
} // END FORK udp
}
////////////////////////////////// web_server //////////////////////////////////////////
if(web)
{
web_server = fork();
if(-1 == web_server)
{
error_log("Not web_PID");
}
if(web_server == 0)
{
read_index_file();
int n2 = 1, client_fd;
struct sockaddr_in svr_addr, cli_addr;
socklen_t sin_len = sizeof(cli_addr);
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sock < 0)
{
close(sock);
error_log("Error - socket web");
}
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &n2, sizeof(n2));
svr_addr.sin_family = AF_INET;
svr_addr.sin_addr.s_addr = INADDR_ANY;
svr_addr.sin_port = htons(PORTW);
if(bind(sock, (struct sockaddr *) &svr_addr, sizeof(svr_addr)) == -1)
{
close(sock);
error_log("Error - web bind");
}
if(listen(sock, 5) == -1)
{
close(sock);
error_log("Error - listen");
}
char buffer[BUFSIZE] = {0,};
char bufRec[BUFSIZE] = {0,};
while(1)
{
client_fd = accept(sock, (struct sockaddr *) &cli_addr, &sin_len);
if(client_fd == -1)
{
continue;
}
web_server2 = fork();
if(-1 == web_server2)
{
error_log("Not web_2_PID");
}
if(web_server2 == 0)
{
unsigned int i = 0;
unsigned int ir = 0;
memset(bufRec, 0, sizeof(bufRec));
memset(buffer, 0, sizeof(buffer));
read(client_fd, buffer, BUFSIZE - 1);
if((strstr(buffer, "GET")) != NULL)
{
if((strstr(buffer, "curl")) != NULL) //////////////////////////// Curl
{
printf("OK_Curl\n");
for(; i <= strlen(buffer); i++)
{
if(buffer[i] == '/')
{
i++;
for(; i <= strlen(buffer); i++)
{
bufRec[ir] = buffer[i];
ir++;
if(buffer[i] == '\r' || buffer[i] == '\n')
{
bufRec[ir] = 0;
break;
}
}
break;
}
}
memset(buffer, 0, sizeof(buffer));
char *p;
if((p = strstr(bufRec, "HTTP")) != NULL)
{
int index = p - bufRec;
int i = 0;
for(; i <= index - 2; i++)
{
buffer[i] = bufRec[i];
}
buffer[i] = 0;
memset(bufRec, 0, sizeof(bufRec));
snprintf(bufRec, BUFSIZE - 1, "echo '%s' > %s", buffer, device);
system(bufRec);
printf("Curl_send_toArdu: %s\n", bufRec);
}
memset(bufRec, 0, sizeof(bufRec));
memset(buffer, 0, sizeof(buffer));
usleep(PAUSARD);
FILE *f;
f = fopen(file_ardu_patch, "r"); // файл ардуины
if(f == NULL)
{
close(client_fd);
error_log("Error-NOT open file");
}
fgets(buffer, BUFSIZE - 1, f);
fclose(f);
snprintf(bufRec, BUFSIZE - 1, "%s\r\n", buffer);
write(client_fd, bufRec, sizeof(bufRec));
close(client_fd);
printf("Send to curl_client: %s\n", bufRec);
exit(0);
}
else //////////////////////////////////////////////////////////////// GET
{
printf("OK_GET\n");
for(; i <= strlen(buffer); i++)
{
if(buffer[i] == '=')
{
i++;
for(; i <= strlen(buffer); i++)
{
bufRec[ir] = buffer[i];
ir++;
if(buffer[i] == '\r' || buffer[i] == '\n')
{
bufRec[ir] = 0;
break;
}
}
break;
}
}
memset(buffer, 0, sizeof(buffer));
char *p;
if((p = strstr(bufRec, "HTTP")) != NULL)
{
int index = p - bufRec;
int i = 0;
for(; i <= index - 2; i++)
{
buffer[i] = bufRec[i];
}
buffer[i] = 0;
memset(bufRec, 0, sizeof(bufRec));
snprintf(bufRec, BUFSIZE - 1, "echo '%s' > %s", buffer, device);
system(bufRec);
printf("GET_send_toArdu: %s\n", bufRec);
}
}
}
else
{
printf("NOT GET or Curl\n");
close(client_fd);
exit(0);
}
memset(bufRec, 0, sizeof(bufRec));
memset(buffer, 0, sizeof(buffer));
usleep(PAUSARD);
FILE *f;
f = fopen(file_ardu_patch, "r"); // файл ардуины
if(f == NULL)
{
close(client_fd);
error_log("Error-NOT open file");
}
fgets(buffer, BUFSIZE - 1, f);
fclose(f);
snprintf(bufRec, BUFSIZE - 1, "%s", buffer);
write(client_fd, response, sizeof(response) - 1);
write(client_fd, index_file, BUFSIZE);
write(client_fd, bufRec, BUFSIZE);
close(client_fd);
printf("Send to web_client: %s\n", bufRec);
exit(0);
} // END FORK web2
close(client_fd);
wait(NULL);
} // END while
} // END fork web
} // END web
/////////////////////////////////////////// SEND UDP //////////////////////////////////////////////
if(udp_c)
{
if((sockfd=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
{
close(sockfd);
error_log("Not sockfd");
}
int n1 = 1;
setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&n1,sizeof(n1));
host = gethostbyname(adr_udp);
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(PORTS);
server.sin_addr = *((struct in_addr*) host->h_addr);
}
/////////////////////////////////////////// READ ARDUINO //////////////////////////////////////////////
unsigned int i;
while(!VINTR)
{
int bytes = 0;
memset(bRead, 0, sizeof(bRead));
if((bytes = read(fd, bRead, BUFSIZE))==-1) // read()
{
printf("Error_Read_from_Arduino\n");
}
for(i = 0; i <= strlen(bRead); i++)
{
if(bRead[i] == '\n')
{
bRead[i] = 0;
break;
}
}
//////////////////// Сравнение строк //////////////////////
if(strcmp(bRead, str_iz_file)==0)
{
printf("Str_equally\n");
}
else
{
printf("Str_NOT_equally\n");
FILE *f;
f = fopen(file_ardu_patch, "w");
if(f == NULL)
{
error_log("Error-Write to file");
}
fprintf(f, "%s", bRead);
fclose(f);
memcpy(str_iz_file, bRead, sizeof(str_iz_file));
}
printf("Reciv_from_arduino: %s | Bytes - %d\n", bRead, bytes);
if(udp_c)
{
if(sendto(sockfd, str_iz_file, strlen(str_iz_file), 0, (struct sockaddr *) &server, sizeof(struct sockaddr_in)) < 0)
{
error_log("ERROR_udp_send");
}
printf("UDP_send: %s\n\n", str_iz_file);
}
} // END (while)
return 0;
} // END main()
// gcc -Wall -Wextra ardunetstd.c -o ardunetstd
###########################################
##########Makefile Openwrt#################
###########################################
include $(TOPDIR)/rules.mk
PKG_NAME:=ardunetstd
PKG_VERSION:=1
PKG_RELEASE:=1
PKG_BUILD_DIR:= $(BUILD_DIR)/$(PKG_NAME)
include $(INCLUDE_DIR)/package.mk
define Package/ardunetstd
SECTION:=utils
CATEGORY:=Utilities
TITLE:=ardunetstd - ArduNetstD utility
endef
define Package/ardunetstd/description
ardunetstd - ArduNetstD utility
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Build/Compile
$(TARGET_CC) $(TARGET_CFLAGS) -c -o $(PKG_BUILD_DIR)/ardunetstd.o $(PKG_BUILD_DIR)/ardunetstd.c
$(TARGET_CC) $(TARGET_LDFLAGS) -o $(PKG_BUILD_DIR)/ardunetstd $(PKG_BUILD_DIR)/ardunetstd.o
endef
define Package/ardunetstd/install
$(INSTALL_DIR) $(1)/
$(INSTALL_BIN) $(PKG_BUILD_DIR)/ardunetstd $(1)/
endef
$(eval $(call BuildPackage,ardunetstd))
// make package/ardunetstd/compile V=s
GitHub
- +154
- stD
22696
Поддержать автора
Комментарии (71)
На днях обновил убунту, стояла 14.04.1 х64, до 16.04.1 х64 и при запуске ругается:
если без sudo, то так:
и даже если в папку зайти и от туда запустить, то
Куда можно капнуть? Или в убунте новой что-то изменилось и ardunetstd не желает с ней контачить?
Может так? А Вы путь то к файлу не путаете?
Из установленного только apache2+nginx+php+mysql по вашей статье. Может быть я что-то не доустановил для работы вашего сервера?
Скачали, положите его и файл index.web в домашнюю папку, сделайте:
Запускайте.
то сразу данные от ардуины летят. А на серваке, где ругается на ardunetstd, после такой команды тишина. Только в ардуину отправить можно.
Вы же пишите…
.
Всё победил проблему. Вобщем я как и думал что не доустановил что-то после обновления.
и всё заработало. Спс за помощь.
Если при запущенном ardunetstd отключить ардуину, терминал начинает выдавать ошибку и не прекращает при повторном подключении. Лечится это только перезапуском процесса. Как можно сделать так, чтобы при отключении ардуины, ardunetsd просто завершал свою работу?