RPi: Первый опыт

Пришла мне малинка и надо было уже что-то начинать делать :)

Первым делом я установил на борт линукс Raspbian, правда флешку пришлось докупать у нас, с китайской линукс заводится упорно отказывался. Процесс установки и настройки я описывать не буду, этого добра в инете навалом.

Проблема: мой adsl модем периодически подвисает, как следствие инет полностью отваливается, помогает в этом случае полный ребут модема. Как правило, несколько раз за день приходится повторять данное действие.

Предполагаемое решение проблемы: Проверять доступность какого-либо сайта раз в n минут, в случае его недоступности делать ребут модема.

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

Сначала я думал даже брать питалово прямо из модема, и уже начал было искать бп помощнее, и думать как добавить проходной транзик для внутренней 78D05. Но потом понял, что решение будет не универсальным и не оправданным – для данной задачи подойдет обычный блок питания.

Для управления внешним устройством нам понадобятся порты ввода-вывода, т.к. я привык к C, то естественно искал наиболее удобный тул для работы именно в C. Для меня этим удобным тулом стал wiringPi.

Все хорошо расписано на их сайте, там же находим и пример работы. Единственное, что может запутать это распиновка, поэтому привожу картинку из источника на всякий пожарный:

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

gcc -Wall -o execfilename cfilename.c -lwiringPi
sudo ./execfiname

Сами примеры можно найти на вышеуказанном сайте, никаких проблем, все работает.

Ок, мы знаем как дергать порты ввода/вывода, теперь надо сварганить непосредственно анализ доступности сайта.

Немного погуглив, я для себя сделал вывод, что наиболее безболезненный способ – это использование функции “popen”. С ее помощью можно вызывать существующие приложения внутри своего кода.

Вот как это примерно выглядит:


#include <stdio.h>
#include "/usr/include/string.h"
#include "/usr/include/stdlib.h"

int main ()
{

FILE *cmd = popen ( "ping -c 4 ya.ru", "r" ); //ping ya.ru 4 раза
char *s = malloc ( sizeof ( char ) * 200 );
while ( 1 )
{
  fgets ( s, sizeof ( char )*200, cmd );
  printf ( "%s", s);//show outcome
  if ( strstr ( s, "icmp_rec" ) != 0 )    //проверяем есть ли нужная инфа
                      break;
}

pclose ( cmd );
return 0;
}

Пробуем наш код:


root@PIhorse:/home/pi/Buf# gcc -Wall -o ConnectTest ping3.c
root@PIhorse:/home/pi/Buf# ./ConnectTest
PING ya.ru (93.158.134.3) 56(84) bytes of data.
64 bytes from www.yandex.ru (93.158.134.3): icmp_req=1 ttl=52 time=34.3 ms

Вроде как все ок :)

Фактически у нас есть инструмент проверки и инструмент выполнения, остается железная часть.

Здесь вообще все просто: один транзистор и реле:

Можно все собирать в кучу. Я еще добавил некое программное подобие вотчдога на 60 секунд, если у нас за минуту ничего не вывалилось, то значит надо делать ребут и останавливать программу. Для работы со временем я использовал библиотеку dev/time.h.

Для примера и проверки попытаемся проверить несуществующий сайт, и если никуда не достучимся в течении 5 секунд, то ресетнем наш модем.


#include <stdio.h>
#include "/usr/include/string.h"
#include "/usr/include/stdlib.h"
#include <sys/time.h>
#include <wiringPi.h>

int main ()
{
wiringPiSetup();        //Init wiringPi
pinMode (0, OUTPUT);    //GPIO 0 на выход
digitalWrite (0, LOW);  //и в 0 его сразу
double t1, t2;
unsigned char flag = 0;
struct timeval tim;
gettimeofday(&tim, NULL);
t1=tim.tv_sec+(tim.tv_usec/1000000.0);  //Время старта в секундах
FILE *cmd = popen ( "ping -c 4 razdvatridvaodin.ru", "r" ); //ping ya.ru 4 раза
char *s = malloc ( sizeof ( char ) * 200 );
do
 {
  fgets ( s, sizeof ( char )*200, cmd );
  printf ( "%s", s);//show outcome
  gettimeofday(&tim, NULL);
  t2 = tim.tv_sec+(tim.tv_usec/1000000.0);  //Текущее время работы в секундах
  if ( strstr ( s, "ms" ) != 0 )    //проверяем допинговались ли мы куда-нибудь вообще, если да то прерываем цикл
   {
     flag = 1;
     break;
   }
 }while((t2-t1)<5);        //Если висим слишком долго то пора делать ребут

if (!flag)                 //Обрабатываем отсутствие коннекта
{
  digitalWrite (0, HIGH);
  delay(1000);
  delay(1000);
  digitalWrite (0, LOW);
}

pclose ( cmd );
return 0;
}

А вот и результат:

Делэи, кстати, весьма точно отрабатываются.

По итогу код выглядит как-то так:


#include <stdio.h>
#include "/usr/include/string.h"
#include "/usr/include/stdlib.h"
#include <sys/time.h>
#include <wiringPi.h>

int main ()
{
wiringPiSetup();        //Init wiringPi
pinMode (0, OUTPUT);    //0 пин на выход
digitalWrite (0, LOW);  //пока не трогаем его
double t1, t2;
unsigned char flag = 0;
struct timeval tim;
gettimeofday(&tim, NULL);
t1=tim.tv_sec+(tim.tv_usec/1000000.0);  //Время старта в секундах
FILE *cmd = popen ( "ping -c 4 ya.ru", "r" ); //ping ya.ru 4 раза
char *s = malloc ( sizeof ( char ) * 200 );
do
{
   fgets ( s, sizeof ( char )*200, cmd );
   printf ( "%s", s);//show outcome
   gettimeofday(&tim, NULL);
   t2 = tim.tv_sec+(tim.tv_usec/1000000.0);  //Текущее время работы в секундах
   if ( strstr ( s, "ms" ) != 0 )    //проверяем допинговались ли мы куда-нибудь вообще, если да то прерываем цикл
   {
       flag = 1;                     //устанавливаем флаг
       break;                        //выходим из цикла
   }
}while((t2-t1)<60);        //Если висим слишком долго то пора делать ребут

if (!flag)                 //Обрабатываем отсутствие коннекта
{
  digitalWrite (0, HIGH);
  delay(1000);
  delay(1000);
  digitalWrite (0, LOW);
}

pclose ( cmd );
return 0;
}

Отлично, у нас есть какой-то код, который даже работает, теперь надо бы заставить его запускаться по расписанию (=каждые n минут). Для этих целей можно использовать службу cron, хелп по которой можно найти прямо на сайте raspberry PI. Но вот тут пишут, что продвинутые юзеры так не делают, почему хз, но будем косить под продвинутых :)

Для проверки сервиса я нарыл простой код, который пишет текущее время в файл


#include <time.h>
#include <stdio.h>

int main( void )
{
FILE * fp;
fp = fopen ("/home/pi/Buf/file.txt", "a+");
time_t t;
time(&t);
fprintf( fp, "The time is %s\n", ctime( &t) );

fclose(fp);

return 0;

}

Таким образом будет хорошо видно, когда команда была запущена.

Компилируем прогу, присваем ей имя TimeIs и топаем в /etc/cron.d, там создаем файлик mycronjob со следующим содержанием:


*/1 * * * * root /home/pi/Buf/./TimeIs

Что означает, что наша программа будет запускаться каждую минуту. Ждем пару минут и собираем данные о работе:


The time is Sun Jul 20 18:38:01 2014

The time is Sun Jul 20 18:39:02 2014

The time is Sun Jul 20 18:40:01 2014

The time is Sun Jul 20 18:41:01 2014

The time is Sun Jul 20 18:42:01 2014

The time is Sun Jul 20 18:43:01 2014

Все четко отрабатывает.

И в этот момент я осознал, что мне еще неплохо бы заиметь логи работы моей программы, так что финальный штрих проявляется в виде добавления пару строк с кодом


if (!flag)                 //Обрабатываем отсутствие коннекта
{
digitalWrite (0, HIGH);
delay(1000);
delay(1000);
digitalWrite (0, LOW);

fprintf( fp, "Test of connection failed at %s\n", ctime( &t) );
} else
fprintf( fp, "Test of connection passed at %s\n", ctime( &t) );

Благодаря этому я буду видеть работает ли вообще мое улучшение или нет.

Выставляем срабатывание в кроне на 10 минут и мы готовы к бою :)

А да, несколько фоток извращений, в стиле “ад для перфекциониста”

До:

После:


P.S. Последнюю версию исходника можно найти здесь.

RPi: Первый опыт: 10 комментариев

  1. а новый модем не лучше будет ? )))

    Ответить

    sarge Ответил:

    Это не наш метод :)
    Да и модем мой личный, а не от провайдера, да и достался на халяву…

    Ну все равно мне надо было попробовать подергать портами ввода-вывода (:

    Ответить

    electronic255 Ответил:

    надо будет как нибудь RPi приобрести, интересная штука. на нее только Linux ставится?

    Ответить

    electronic255 Ответил:

    кстати,где заказывал?

    Ответить

    sarge Ответил:

    Ну я видел только линуксоподобные дистры, да и смысл туда что-то другое всовывать на такой конфиг :)

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

    Ответить

    electronic255 Ответил:

    у меня что то али не принимает мою банковскую карту :(

    Ответить

    sarge Ответил:

    Странно, у них вроде довольно широкий спектр возможностей, даже киви и вебмани можно.

    К слову, я ща большинство комплектухи именно там заказываю.

    Ответить

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.