cosmo-gsm-connect библиотека
  • Иван, добрый день.
    Помогите разобраться с конструкцией команд, например выключение модема:

    s8 GSMClass::PowerOFF()
    {
    GSM.WriteStr_P(PSTR("AT\r\n")); отправляем в модем команду АТ которая его разбудит если он уснул
    _delay_ms(500); пауза
    UART0_rx_reset( ); чистим буфер приёма
    UART0_setSearchString( OK_ ); задаём то, что ожидаем получить от модема
    GSM.WriteStr_P(PSTR("\r\nAT$POWEROFF\r\n")); отправляем команду на выключение
    UART0_rx_on( ); переводим порт в режим приёма данных
    if( UART0_check_acknowledge( 256 ) > 0 ) тут два цикла, один из которых завязан на флаг подтверждения (rx_ack)
    {
    return 1;
    }
    else return -1;
    }

    просвятите что это за флаг подтверждения и правильно ли я понимаю алгоритм работы комманды.
  • MDV said:

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


    Добрый день!
    Да, вы правильно описали алгоритм.
    Касательно флага rx_ack
    Он выставляется, когда в UART получен новый символ.
    Подробнее можете глянуть в функции ISR.
  • Иван а как происходить сравнение пришедшего ответа с тем что прописан в строке предшедствующей отправке АТ команды.
  • Не совсем понял, насчет "строке предшедствующей отправке".
    Пишем пришедшие в UART символы в буфер, а потом ищем нужные нам ответы
    searchFor = (const char*)pgm_read_word(&searchStrings[CRLF_]);
  • Спасибо вроде разобрался.
  • Иван, добрый день.
    помогите еще плиз.
    не могу понять по какой команде происходит загрузка данных в сокет
    "// Вот тут и записываем в сокет данные
    (CALLBACK_FUNC)(&putchar);
    // while (*DATA) putchar(*DATA++);
    "
  • MDV said:

    не могу понять по какой команде происходит загрузка данных в сокет


    В смысле - по какой команде?

  • перефразирую как происходит отправка данных после того как соединение установлено?
    "// Вот тут и записываем в сокет данные
    (CALLBACK_FUNC)(&putchar); CALLBACK_FUNC не понятно откуда береться.
    // while (*DATA) putchar(*DATA++); это кусочек не работает так как закоментирован
    "
  • А, теперь понятен ваш вопрос :)
    CALLBACK_FUNC - это переменная,
    вот смотрите как SocketTCPWrite используется в скетчах:
    while (GSM.SocketTCPWrite(ISP_IP, LOGIN, LOGIN, PSTR("map.net13.info"), 8283, &Narodmon.TelnetSend) < 0) { ...
    В этом примере CALLBACK_FUNC - это Narodmon.TelnetSend

    Гляньте пример в https://github.com/jt5/narodmon
  • то есть если я правильно понимаю
    (CALLBACK_FUNC)(&putchar); где CALLBACK_FUNC данные которые необходимо передать, а &putchar комманда которая выводит даные в порт.
  • посмотрел но как то не понял.
    void NarodmonClass::TelnetSend ( unsigned char (*PutSocket) (unsigned char))
    {
    unsigned char* pSrc; // Временный указатель
    char i2a_buf[6]; //Временный буфер
    char* pi2a; // и его указатель
    if (NarodmonData.NUM_SENSORS == 0) return; // Если нет датчиков, то ничего не отправляем

    // Отправляем MAC адрес устройства
    (PutSocket)('#');
    pSrc = NarodmonData.MAC_ID;
    for (unsigned char n = 0; n < 15; n++)
    {
    (PutSocket)(NarodmonData.MAC_ID[n]);
    }
    (PutSocket)('\n');
    // Отправляем данные с датчиков
    for (unsigned char i = 0; i < NarodmonData.NUM_SENSORS; i++)
    {
    (PutSocket)('#');
    // Для каждого датчика отправим его MACn
    pSrc = &NarodmonData.MAC_SENSORS[i][0];
    for (unsigned char n = 0; n < 8; n++)
    {
    //Декодируем MACn датчика по байтам
    i2hex(*pSrc++, i2a_buf, 2);
    pi2a = i2a_buf;
    while (*pi2a) (PutSocket)(*pi2a++);
    }
    (PutSocket)('#');
    // Тпеерь декодируем и отправляем данные
    signed int Datax10 = NarodmonData.DATA_SENSORS[i]; //Cчитали данные
    if (Datax10 < 0)
    {
    (PutSocket)('-'); // если значение отрицательное, то отправляем '-'
    Datax10 = -Datax10; //преобразовали в положительное
    }
    // Преобразуем двоичное в десятичное
    i2a((unsigned int) (Datax10 / 10), i2a_buf);
    pi2a = i2a_buf;
    while (*pi2a) (PutSocket)(*pi2a++);
    (PutSocket)('.');
    i2a((unsigned int) (Datax10 % 10), i2a_buf);
    pi2a = i2a_buf;
    while (*pi2a) (PutSocket)(*pi2a++);
    (PutSocket)('\n');
    }
    (PutSocket)('#');
    (PutSocket)('#');
    }


    только в этой библиотеке нет CALLBACK_FUNC
    в этом примере s8 GSMClass::SocketTCPWrite(const char* ISP_IP, const char* LOGIN, const char* PWD, const char* SERVER_IP, unsigned int SERVER_PORT, void (*CALLBACK_FUNC)(unsigned char(*SocketWr)(unsigned char)))
    {
    GSM.WriteStr_P(PSTR("AT\r\n"));
    _delay_ms(500);
    UART0_rx_reset( );
    UART0_setSearchString( OK_ );
    GSM.WriteStr_P(PSTR("\r\nAT$NOSLEEP=1\r\n"));
    UART0_rx_on( );
    if( UART0_check_acknowledge(63) <= 0 )
    {
    return -5;
    }
    UART0_rx_reset( );
    UART0_setSearchString( OK_ );
    GSM.WriteStr_P(PSTR("\r\nAT+CGDCONT=1,\"IP\",\""));
    GSM.WriteStr_P(ISP_IP);
    GSM.WriteStr_P(PSTR("\"\r\n"));
    UART0_rx_on( );
    if( UART0_check_acknowledge(2560) > 0 )
    {
    UART0_rx_reset( );
    // _delay_ms(500);
    UART0_setSearchString( OK_ );
    GSM.WriteStr_P(PSTR("\r\nAT%CGPCO=1,\"PAP,"));
    GSM.WriteStr_P(LOGIN);
    putchar(',');
    GSM.WriteStr_P(PWD);
    GSM.WriteStr_P(PSTR("\",1\r\n"));
    UART0_rx_on( );
    if( UART0_check_acknowledge( pause256) > 0 )
    {
    UART0_rx_reset( );
    //_delay_ms(500);
    UART0_setSearchString( OK_ );
    GSM.WriteStr_P(PSTR("\r\nAT$DESTINFO=\""));
    GSM.WriteStr_P(SERVER_IP);
    GSM.WriteStr_P(PSTR("\",1,"));
    i2a(SERVER_PORT, i2a_buf);
    char* pi2a = i2a_buf;
    while (*pi2a) putchar(*pi2a++);
    GSM.WriteStr_P(PSTR(",1\r\n"));
    UART0_rx_on( );
    if( UART0_check_acknowledge( pause64) > 0 )
    {
    UART0_rx_reset( );
    //_delay_ms(500);
    UART0_setSearchString( OK_ );
    GSM.WriteStr_P(PSTR("\r\nAT$TIMEOUT=1000\r\n"));
    UART0_rx_on( );
    if( UART0_check_acknowledge(63) <= 0 ) return -7;
    UART0_rx_reset( );
    //_delay_ms(500);
    UART0_setSearchString( OK_ );
    GSM.WriteStr_P(PSTR("\r\nATD*97#\r\n"));
    UART0_rx_on( );
    if( UART0_check_acknowledge(2560) > 0 ) получили подтверждение что сокет открыт для передачи данных
    {
    // Вот тут и записываем в сокет данные
    (CALLBACK_FUNC)(&putchar); а вот тут не понятно
    // while (*DATA) putchar(*DATA++);
    _delay_ms(1000);
    GSM.WriteStr_P(PSTR("+++"));//Разрываем соединение
    _delay_ms(1000);
    GSM.WriteStr_P(PSTR("ATH0"));
    _delay_ms(2000);
    }
    else
    {
    _delay_ms(1000);
    GSM.WriteStr_P(PSTR("+++"));//Разрываем соединение
    _delay_ms(1000);
    GSM.WriteStr_P(PSTR("ATH0"));
    _delay_ms(2000);
    return -4;
    }
    }else return -3;
    } else return -2;
    } else return -1;
    return 1;
    }
  • (CALLBACK_FUNC)(&putchar); а вот тут не понятно

    CALLBACK_FUNC - это функция (которая вызывается, например TelnetSend)
    putchar - это данные, которые передаются в TelnetSend.

  • Иван добрый день.
    Как непосредственно или где идет присваение callback telnet
  • MDV said:

    Как непосредственно или где идет присваение callback telnet


    Конкретно - в скетче, пример.
  • Иван, добрый день.
    Есть еще вопрос
    при инициализации модема в с случае ответа еррор по команде AT+CGATT происходит зависание, если я правильно понимамаю, то это именно програмный баг, так как при повторной инициализации модема происходит повторное передергивание уровней, что приводит к отключению модема.

    s8 GSMClass::Init(const char* PIN)
    {
    DDRD |= (1<<PD7)|(1<<PD6);
    PORTD &= ~(1<<PD6);
    PORTD |= (1<<PD7);
    _delay_ms(500);
    PORTD &= ~(1<<PD7);
    _delay_ms(500);
    PORTD |= (1<<PD6);
    _delay_ms(500);
    PORTD &= ~(1<<PD6);
    _delay_ms(500);

    UART0_init();
    GSM.WriteStr_P(PSTR("AT\r\n"));
    // _delay_ms(100);
    GSM.WriteStr_P(PSTR("ATE0\r\n"));
    _delay_ms(500);
    GSM.WriteStr_P(PSTR("AT+IFC= 0,0\r\n"));
    // _delay_ms(500);

    // searchFor = (const char*)pgm_read_word(&searchStrings[1]);
    // GSM.WriteStr_P(searchFor);
    sei();
    do
    {
    UART0_rx_reset( );
    UART0_setSearchString( OK_ );
    // _delay_ms(500);
    GSM.WriteStr_P(PSTR("AT\r\n"));
    UART0_rx_on( );
    } while( UART0_check_acknowledge( pause64 ) <= 0 );


    UART0_rx_reset( );
    UART0_setSearchString( OK_ );
    // _delay_ms(500);
    GSM.WriteStr_P(PSTR("ATE0\r\n"));
    sei();
    UART0_rx_on( );
    if( UART0_check_acknowledge( pause64) > 0 )
    {
    UART0_rx_reset( );
    // _delay_ms(500);
    UART0_setSearchString( CPIN_ );
    GSM.WriteStr_P(PSTR("AT+CPIN?\r\n"));
    UART0_rx_on( );
    if( UART0_check_acknowledge( pause256 ) > 0 )
    {
    //Пришел ответ "+CPIN:"
    UART0_setSearchString( OK_ );
    UART0_rx_on( );
    if( UART0_check_acknowledge( pause64 ) > 0 )
    {// Пришел ответ OK
    if (strstr_P((char*)rx_buffer, PSTR("SIM PIN")))
    {
    // Необходимо ввести PIN CODE
    UART0_rx_reset( );
    //_delay_ms(500);
    UART0_setSearchString( OK_ );
    GSM.WriteStr_P(PSTR("AT+CPIN=\""));
    GSM.WriteStr_P(PIN);
    GSM.WriteStr_P(PSTR("\"\r\n"));
    UART0_rx_on( );
    if( UART0_check_acknowledge(pause256 ) > 0)
    {
    // Пин-код верный
    goto L_INIT;
    }
    else return -3;
    }
    else if (strstr_P((char*)rx_buffer, PSTR("READY")))
    {
    // Pin вводить не надо
    goto L_INIT;
    }
    else return -2;
    }
    else return -2;
    }
    else return -2;
    }
    else return -1;
    L_INIT:
    /*
    Патч: проверим, надо ли регистрироваться в сети?
    */
    if (CheckStatus() == 1) goto L_INIT_01;
    UART0_setSearchString( OK_ );
    UART0_rx_reset( );
    //_delay_ms(500);
    GSM.WriteStr_P(PSTR("AT+CGATT=1\r\n"));
    UART0_rx_on( );
    if( UART0_check_acknowledge( 3840 ) > 0 )
    {
    // Запрос СМС центра
    // GSM.WriteStr_P(PSTR("AT+CSCA?\r\n"));
    // _delay_ms(1000);
    //Инициализируем текстовый режим СМС
    L_INIT_01:
    UART0_setSearchString( OK_ );
    UART0_rx_reset( );
    //_delay_ms(500);
    GSM.WriteStr_P(PSTR("AT+CMGF=1\r\n"));
    UART0_rx_on( );
    if( UART0_check_acknowledge( pause64 ) > 0 )
    {
    UART0_rx_reset( );
    //_delay_ms(500);
    GSM.WriteStr_P(PSTR("AT+CLIP=1\r\n"));
    UART0_rx_on( );
    if( UART0_check_acknowledge( pause64 ) > 0 )
    {
    return 1;
    }
    } else return -4;
    }else return -3;
    }

    вопрос это действительно так? или я где то что то не увидел.
  • Команда AT+CGATT - это регистрация в GSM сети.
    Если модем не смог зарегистрироваться, нужно повторно проинициализироваться.
  • это мне понятно, но судя по алгоритму происходит передергивание уровней на уже включенном модеме и это приводит к его отключению.
    у меня зависает зависает именно из за этого. При этом может зависнуть на втрором прогоне цикла иногда на четвертом. Дальше пятого не заходил.
  • Ну, возможно, это не самое элегантное решение. Поэтому исходные коды библиотеки открыты и вы можете под свои нужны оптимизировать ту или иную часть программы.
  • Иван, добрый день.
    Большое спасибо Вам за помощь.
    Если не возражаете в будующем помучаю Вас еще. :-)
  • Иван, добрый день.
    Снова нужна ваша помощь.
    Решил заменить Уно на Мегу и всё перестало работать, такое ощущение что МК не общается с модемом мониторю УАРТ0 а там тишина, смотрю схемы разные потры на МК может у Вас есть решение как вылечить данную болезнь?
  • Наша библиотека написана только под Atmega328.
    С платой Мега - работать не будет.
  • Иван, реально что то переделать в библиотеке или ваш вердик окончательный?
  • ну чтобы работало с Мегой библиотеку нужно править (порты переписывать)
    но мы этим сейчас точно заниматься не будем, нет времени.
  • Иван готов сам править вот только что и как.
    Мне видеться что необходимо править все обращения к порту
    void UART0_init(void)
    {
    DDRD |= (1 << 7);<br /> UCSR0B = 0x00;
    UCSR0A = 0x00;
    UCSR0C = 0x06;
    UBRR0L = 25; //38400 low speed ( @ 16 MHz)
    UBRR0H = 0x00;
    UCSR0B = ( 1 << TXEN0 )|( 1 << RXEN0 ); <br /> UART0_rx_reset();
    }
    вот только на что?
  • посмотрите эту локализованную версию
    http://jt5.ru/files/GSM2560.zip
    по-мойму эта версия библиотеки GSM под мегу.
  • Иван добрый день
    В ней отличие от GSM.cpp только в пинах включающих модем.
    может есть еще мысли
  • Иван добрый день.
    поставил новую версию IDE теперь в порт идут команды, модем на них отвечает, но такое ощущение что контроллер их не понимает, менял платы эфект одинаковый, есть ли мысли в чем может быть проблема.
  • Иван. еще раз добрый день.
    локализовал проблему.
    проблема в софте. при проверке порт-модем команды и ответы проходят без ошибок.
    при заливке скеча плата посылает команду модем дает ответы но конроллер данные ответы не понимает (виснет). пробовал ремить разные ответы эфект одинаковый.
    есть ли какой нибудь тест на низком уровне для проверки как читает контроллер.
  • а микроконтроллер точно получает ответы?
    если есть осциллограф проверьте линии RX/TX сигналы по ним передаются.

    или если есть 2 плата ардуино подключите его к шилду проводками 0->1, 1->0 (RX->TX, TX->RX).
    запустите терминал и смотрите какие ответы отправляет модем на микроконтроллер.
  • Иван добрый день.
    Второй контролер подсоединял ответы от модема правильные но контролер при их обработке виснет, как будто не может разобрать что пришло в буфер. Можно как то прописать что бы контролер отправил в порт то что принял?

Привет, незнакомец!

Похоже, вы новенький! Чтобы пообщаться с нами, кликните на одну из кнопок ниже :)

Войти с помощью OpenID

В этом теме:

  • Ivan Сентябрь 2014
  • MDV Сентябрь 2014