The OpenNET Project / Index page

[ новости /+++ | форум | wiki | теги | ]

форумы  помощь  поиск  регистрация  майллист  вход/выход  слежка  RSS
"Раздел полезных советов: Настройка работы CDMA модема через ..."
Вариант для распечатки  
Пред. тема | След. тема 
Форумы Разговоры, обсуждение новостей (Public)
Изначальное сообщение [ Отслеживать ]

"Раздел полезных советов: Настройка работы CDMA модема через ..."  +/
Сообщение от auto_tips (??) on 13-Ноя-09, 15:21 
++ Окружение

ОС - Fedora 11 (Russian Remix). Ядро 2.6.29.4-167.fc11.i686.PAE. Mодем Maxon Minimax MM-5500U (CDC ACM модем). Файлы /etc/wvdial.conf, /etc/resolv.conf настроены верно. Используется верно настроенная программа дозвона
chestnut-dialer (вер. 0.3.3) (хотя можно и без нее если установлен wvdial).

++ Ситуация 1.

Загружается ОС. Модем отключен. Затем модем включается и дозвон невозможен, поскольку отсутствует файл устройства /dev/ttyACM0.

Мониторинг командой udevadm monitor показывает, что его удаляет ядро и затем Udev.

++ Ситуация 2.

Загружается ОС. Модем включен. Дозвон возможен (файл устройства /dev/ttyACM0 существует). Модем отключается - файл  устройства /dev/ttyACM0 пропадает. При повторном включении модема файл устройства отсутствует. В итоге дозвон невозможен.

++ Решение.

Подобные ситуации возникали, в частности, и в Ubuntu 9.10 и в некоторых других Linux. Из форумов видно, что проблему рекомендуют решать перезагрузкой модуля ядра cdc-acm и созданием файла устройства в командном режиме. Рекомендуют также автоматизацию при помощи правил udev. Возможна даже ситуация когда имеем после нескольких plug/unplug модема множество /dev/ttyACM0..n. И модем не распознается. Правила udev помогают не всегда (установлено экспериментально).

Связь с модемом можно установить и при помощи представленной ниже
специально разработанной программы (тестировалась на Fedora 11 Russian Remix) и Ubuntu 9.10 (версии udev 141 и 147 соответственно).


// File minimaxd.c
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <syslog.h>

#define TMP_FILE__PID         "/tmp/minimaxd.pid"
#define TMP_FILE__LSUSB        "/tmp/lsusbminimax.tmp"
#define PATH_CDC_ACM_MODULE    "/sys/module/cdc_acm/initstate"
#define PATH_MODEM_TTY        "/dev/ttyACM0"
#define CHECK_MODEM_PLUG_STR    "lsusb | grep Qualcomm >   /tmp/lsusbminimax.tmp"

int fileexist(const char* filename);
void kill_copy_daemon();
void start_restart();
void stop();
int CheckPlugModem();
void wait_cdc_acm_control();
int CheckPid();
void SetPid();
int GetPid();
void PrintMessageToLog(char* szMessage);

int main(int argc, char* argv[])
{
   if(argc==2)
   {
     if((!strcmp("start",argv[1]))||(!strcmp("restart",argv[1])))
     {
       kill_copy_daemon();
       wait_cdc_acm_control();
     }
     else
     if(!strcmp("stop",argv[1])) kill_copy_daemon();
   }
   else
   {
      printf("Start/Restart MiniMax Modem Access:\nminimaxd start|stop|restart\n");
     printf("Background start:\nminimaxd start &\n");
   }
   return 0;
}

int fileexist(const char* filename)
{
   int res = 0;
   FILE* f=fopen(filename,"rt");
   if(f!=NULL) { fclose(f); res=1; }
   return res;
}

void kill_copy_daemon()
{
    char cmd[255]="";
    int pid = GetPid();
    if(pid>0)
    {
       kill((pid_t)(pid), SIGKILL);
       strcpy(cmd,"rm -f "); strcat(cmd,TMP_FILE__PID);   system(cmd);
       strcpy(cmd,"rm -f "); strcat(cmd,TMP_FILE__LSUSB); system(cmd);
       PrintMessageToLog("Modem service is stopped");
    }
}

void start_restart()
{
     system("rm -f /dev/modem");
     system("rm -f /dev/ttyACM*");
     system("rmmod cdc-acm");
     system("modprobe cdc-acm");
     system("mknod /dev/ttyACM0 c 166 0");
     system("chmod 666 /dev/ttyACM*");
     system("ln -s /dev/ttyACM0 /dev/modem");
     PrintMessageToLog("Modem service started");
}

void stop()
{
    system("rmmod cdc-acm");
    system("rm -f /dev/modem");
    system("rm -f /dev/ttyACM*");
    PrintMessageToLog("Modem service is stopped");
}

int CheckPlugModem()
{
   char str[255]="";
   int res = 0;

   system(CHECK_MODEM_PLUG_STR);

   sleep(2);

   FILE* f=fopen(TMP_FILE__LSUSB,"rt");
   if(f!=NULL)
   {
     strcpy(str,"");
     fscanf(f,"%s",str);
     fclose(f);
     if(strlen(str)>0) res = 1;
   }
   return res;
}

void wait_cdc_acm_control()
{
   int fl_CDC_ACM_OK=0;
   int fl_ttyACM0_OK=0;
  
   if(!CheckPid())
   {
     SetPid();
    
     while(1)
     {
    fl_CDC_ACM_OK=fileexist(PATH_CDC_ACM_MODULE);
    if(CheckPlugModem())
    {
      fl_ttyACM0_OK=fileexist(PATH_MODEM_TTY);
      
      if((fl_CDC_ACM_OK==1)&&(fl_ttyACM0_OK==0)) start_restart();
      else
      if((fl_CDC_ACM_OK==0)&&(fl_ttyACM0_OK==0)) start_restart();
    }
    else
    {
      if(fl_CDC_ACM_OK) stop();
    }
    sleep(3);
     }
   }
}

int CheckPid()
{
   return fileexist(TMP_FILE__PID);
}

void SetPid()
{
   pid_t pid = getpid();
   FILE* f=fopen(TMP_FILE__PID,"wt");
   if(f!=NULL)
   {
     fprintf(f,"%d",pid);
     fclose(f);
   }
}

int GetPid()
{
   int res = 0;
   FILE* f=fopen(TMP_FILE__PID,"rt");
   if(f!=NULL)
   {
     fscanf(f,"%d",&res);
     fclose(f);
   }
   else res = -3;
   return res;
}

void PrintMessageToLog(char* szMessage)
{
   openlog("MINIMAXD", LOG_ODELAY, LOG_USER);
   syslog(LOG_INFO, "%s", szMessage);
   closelog();
}


Компиляция командой:

   gcc ./minimaxd.c -o minimaxd

Для 64-разрядной версии:

   gcc ./minimaxd.c -m64 -o minimaxd

Полученный minimaxd копируем в каталог /usr/local/bin/
Назначаем владельцем root.

++ Тестирование.

Запуск программы из коммандной строки выполняем так:
  
   # minimaxd start

или в фоне:

   # minimaxd start &

Подключаем модем к usb-порту, ждем инициализации около 5 сек. Затем пробуем дозвон. Прерываем дозвон.

Отсоединяем модем, подсоединяем заново и через 5 сек. повторяем процедуру. Если все Ok, то завершаем процедуру тестирования.
Для завершения работы minimaxd, работающей в фоне, в другой консоли выполняем:

   # minimaxd stop

++ Запуск при загрузке ОС.

В каталоге /etc/rc.d/init.d создаем упрощенный скрипт (файл minimaxdaemon) для менеджмента "демона":


#!/bin/sh
# startup script for Minimax daemon (/usr/local/bin/minimaxd)

DAEMON=/usr/local/bin/minimaxd

minimaxdaemon_start ()
{
     echo -n "Starting ${DAEMON}: "
     ${DAEMON} start &
}

minimaxdaemon_stop ()
{
     echo -n "Shutting down ${DAEMON}: "
     ${DAEMON} stop
}

minimaxdaemon_restart ()
{
     echo -n "Restarting ${DAEMON}: "
     ${DAEMON} restart &
}
  

case $1 in

    start)
        minimaxdaemon_start
        ;;
        
    stop)
        minimaxdaemon_stop
        ;;
    
    status)
        echo "${DAEMON}:" `pidof ${DAEMON}`
        ;;
    
    restart)
        minimaxdaemon_restart
        ;;
    
    *)
        echo "Usage: minimaxdaemon  {start|stop|restart|status}"
        exit 1
        ;;
esac
exit 0


Создаем на minimaxdaemon символические ссылки в каталогах rc?.d. Например, для Fedora 11 (Russion Remix):

   ln -s /etc/rc.d/init.d/minimaxdaemon /etc/rc.d/rc0.d/K01minimaxdaemon
   ln -s /etc/rc.d/init.d/minimaxdaemon /etc/rc.d/rc6.d/K01minimaxdaemon
   ln -s /etc/rc.d/init.d/minimaxdaemon /etc/rc.d/rc5.d/S96minimaxdaemon

Теперь можно проверить работу minimaxd после перезагрузки.

++ Заключение

Следует отметить, что это все верно в случае, если в ядре существует поддержка модуля cdc-acm. Задержки (функции sleep) могут быть выбраны инные. Пример можно рассматривать и для других подобных модемов, работающих через cdc-acm-модуль и использующих /dev/ttyACM0-файл. Однако, надо учесть, что для определения в системе модема используется команда lsusb и в данном случае
она в программе такая:

   lsusb | grep Qualcomm > /tmp/lsusbminimax.tmp

Т.е. подразумевается, что модем определяется, например, как:

   Bus 009 Device 003: ID 05c6:3196 Qualcomm, Inc. CDMA Wireless Modem

Поэтому в программе и фильтруем по слову "Qualcomm".
В случае других производителей управляющую команду надо будет изменить.


URL:
Обсуждается: http://www.opennet.ru/tips/info/2229.shtml

Высказать мнение | Ответить | Правка | Cообщить модератору

Оглавление

Сообщения по теме [Сортировка по времени | RSS]


1. "Настройка работы CDMA модема через /dev/ttyACM0"  +/
Сообщение от Аноним (??) on 13-Ноя-09, 15:21 
Безграмотный (как и "инные") костыль.
Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

2. "Настройка работы CDMA модема через /dev/ttyACM0"  +/
Сообщение от Аноним (??) on 13-Ноя-09, 16:14 
Ну что ж, Аноним, не всем правильно тексты писать.
Зато прога добрая. А udev часто глючит. Ты по сути пиши.
Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

3. "Раздел полезных советов: Настройка работы CDMA модема через ..."  +/
Сообщение от kkk (??) on 14-Ноя-09, 13:07 
Просто волшебно !

Такого идиотского кода на C я не видел лет 15.

Самые перлы:
strcpy(cmd,"rm -f "); strcat(cmd,TMP_FILE__PID);   system(cmd);
system("rm -f /dev/modem");
system("mknod /dev/ttyACM0 c 166 0");
system("ln -s /dev/ttyACM0 /dev/modem");
fscanf без проверки ошибок.
волшебные sleep()

Афтар, напесал бы еще свой шелл-скрипт на ассемблере !

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

4. "Раздел полезных советов: Настройка работы CDMA модема через ..."  +/
Сообщение от Igor (??) on 14-Ноя-09, 13:53 
kkk - да я погляжу Вы Эксперт!
Понимаю Ваш юмор. У меня б наверное первая реакция
такая же была. Но!
Ох и намучился я с этим модемом. Просто кошмар.
Да, в начале и был просто маленький скрипт.
Но проблема в том, что его никак нельзя было
запускать от обычного пользователя (только от root).
Включать пользователя в sudo-поль-ли низя (почему про sudo говорю
надеюсь понимаете).
Связь паршивая, отрубается частенько.
Постоянно надо было как-то переинициализировать среду для
повторного доступа к модему.
Попробовали через udev запускать скрипт при переподключении.
Но к сожалению работало очень (очень!) нестабильно.
Была проведена целая серия различных экспериментов. Но, увы!
В заметке речь идет о конкретных двух ОС. К слову, на
Slackware 12.2 модем работал просто замечательно и ничего
подобного вообще делать нет смысла.
Если Вы знаете как решить эту проблему, то пожалуйста -
код и действия в студию.
А по поводу кода на C - то как известно,
сколько программистов, столько и мнений. Не особенно стремился
к "чистоте" кода в данном случае. Все работает на ура и замечательно.
Проверка fscanf в том месте может и отсутствовать исходя из всей
логики алгоритма.
А sleep - один в цикле, чтоб не очень систему "напрягал". Другой
необходим - поскольку нужна задержка перед выполнением lsusb (отклик системы учесть).
Система абсолютно "не напрягается". Устройство оперативно доступно. Цель достигнута.
P.S.: Если написано плохо, покажите как надо. Вариантов из гугла не предлагать.
Хорошим скриптологам предлагать свои варианты.
Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

5. "Раздел полезных советов: Настройка работы CDMA модема через ..."  +/
Сообщение от kkk (??) on 14-Ноя-09, 14:20 
>kkk - да я погляжу Вы Эксперт!

У Вас Видение !

system("rm -f /dev/modem"); <-- unlink(2)
system("mknod /dev/ttyACM0 c 166 0"); <-- mknod(8)
system("ln -s /dev/ttyACM0 /dev/modem");  <-- symlink(2)

int fileexist(const char* filename)
{
   int res = 0;
   FILE* f=fopen(filename,"rt");
   if(f!=NULL) { fclose(f); res=1; }
   return res;
} <-- stat(2)

void kill_copy_daemon();
void start_restart(); <-- такая чудная вещь, как прототипы

написали бы трех-строчную C-программку, которая бы делала execve(2) скрипта

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

6. "Раздел полезных советов: Настройка работы CDMA модема через ..."  +/
Сообщение от Igor (??) on 14-Ноя-09, 14:28 
:)
Не хотелось скрипт за программой тягать.
Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

7. "Раздел полезных советов: Настройка работы CDMA модема через ..."  +/
Сообщение от Igor (??) on 14-Ноя-09, 14:33 
На счет stat(2) - это да. Верно. Даже как-то
и не сообразил.
Про unlink(2) и symlink(2) - каюсь.
Спасибо.
Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

8. "Раздел полезных советов: Настройка работы CDMA модема через ..."  +/
Сообщение от kkk (??) on 14-Ноя-09, 14:59 
mknod(2), конечно же.

Код
   if(!CheckPid())
   {
     SetPid();
содержит race(), почитайте про флаг O_EXCL у open(2)

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

9. "Раздел полезных советов: Настройка работы CDMA модема через ..."  +/
Сообщение от Igor (??) on 14-Ноя-09, 15:19 
По поводу unlink, mknod, symlink - откровенно говоря было
лень переделывать строки из шелл-скрипта.

>> Код ... содержит race()

Имеется ввиду, что может возникнуть блокировка файла /tmp/minimaxd.pid?
Возможно. Но каким образом.
К файлу обращается только одна запущенная копия процесса. Это
достигается вызовом в программе функции kill_copy_daemon().
Или Вы подразумеваете, что какой-либо другой процесс
может обратиться к этому файлу?
В любом случае, спасибо за дельные советы.

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

Архив | Удалить

Индекс форумов | Темы | Пред. тема | След. тема




Спонсоры:
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2020 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру