05 октября 2019 г
Arduino. http запрос. sim800c. Отладка.
Плата Arduino Uno и SIM800c GPRS/GSM Shield
драйвер для USB-UART CH340/CH341 (Windows)
Блок питания (например, такой)
код скетча.
#define INTERVALSEND 60000
#define response_size 100
#define data_buffer_size 301
#include <SoftwareSerial.h>
unsigned int TextToInt(char * DataLenRead);
SoftwareSerial GPRS(7, 8);
int onModulePin= 9;
unsigned long previous;
char response[response_size]; // это буфер для служебного текста ответов сервера
char data_buffer[data_buffer_size]; // это буфер для полезных данных, полученных из ответов сервера
char userText;
uint8_t answer;
uint8_t read_answer_httpread(const char * firstPart, const char * secondPart, const char * thirdPart, unsigned int * lengthData );
uint8_t read_answer_HTTP_GPRS(const char * AtCommand, const char * expected_answer, char * DataLen);
uint8_t get_SMSdata_http(void);
void setup()
{
GPRS.begin(19200);
Serial.begin(9600);
Serial.println("Starting...");
//pinMode(onModulePin,OUTPUT);
//power_on(); // не работает
delay(3000);
}
void loop()
{
//если отправляем 'g' через монитор порта, то запускается инициализация gprs.
//далее отправляем 'h' для http запросов.
// http соединение каждый раз открывается , делается запрос и оно завершается. Но если возникла ошибка , то соединение не закрылось
// и его инициализировать не нужно. Но так как пока http-запрос проходит полный цикл, то нужно закрыть незавершенное соединение
// и это команда 't'. Закрыть gprs - 'q'.
if ( Serial.available() > 0 ){
userText = Serial.read();
while ( Serial.available() > 0 )
Serial.read();
if (userText == 'g'){
Serial.println("Start GPRS...");
answer = start_GPRS();
if (answer != 0)
Serial.println("\nStart GPRS error.\n");
//goto Ext1;
}
if (userText == 'h') { /////--HTTP--/////
Serial.println("\nBegin HTTP request.\n");
answer = get_SMSdata_http(); // данные от вэб сервера пишу в data_buffer[]
if (answer != 0){
Serial.println("\nHTTP error.\n");
//goto Ext1;
}
// обработка полученных данных
}
if (userText == 't') {
read_answer_HTTP_GPRS("AT+HTTPTERM", "", NULL);
Serial.println(response);
}
if (userText == 'q') {
read_answer_HTTP_GPRS("AT+SAPBR=0,1", "", NULL);
Serial.println(response);
}
}
delay(3000);
} // main loop //////////////////////////////
unsigned int TextToInt(char * DataLenRead){
unsigned int c, rez = 0;
for ( c = 0; c < strlen(DataLenRead); c++ ){
rez = rez * 10 + (unsigned int) DataLenRead[c] - 48; // 0x30h
}
return rez;
}
// переделать описание !
// нужно парсить ответ сервера на команду AT+HTTPREAD
// пересмотреть этот шаг //1. в параметры команды AT+HTTPREAD передаем количество байт (получили на предыдущем шаге)
// 2. вначале ответа получаем копию нашей команды (AT+HTTPREAD).
// 3. далее должно быть типа "+HTTPREAD:175". Тут вытаскиваем фактическое количество полученных байт (в идеале такое же)
// 4. после этого считываем ответ дальше и когда прочитали нужное (пришедшее) количество (т.е. 175), то
// 5. начинаем "завершение" считывания. то есть в оставшемся куске должно быть подтверждающее "ОК" (здесь
// мы уже ВНЕ полезного ответа и "ОК" - это завершающие символы от сервера, а не часть полезных данных.
// (за "ОК" будет ещё перевод строки \r\n)
uint8_t read_answer_httpread(const char * firstPart, const char * secondPart, const char * thirdPart, unsigned int * lengthData ){
unsigned long previous;
uint8_t x, y, answer;
int avail;
int c;
char * istr;
char DataLenRead[10];
unsigned int poleznieBytes = 0, DataLenReadNumber;
int pars = 0, stepP = 0;
x = 0;
y = 0;
answer = 1; // !!! решить вопрос . добавить в код возврат answer == 1, обработать "ERROR", сейчас только по timeout
previous = millis();
while( GPRS.available() > 0)
GPRS.read(); // Clean the input buffer
memset(response, '\0', response_size); // Initialize the string
GPRS.println(firstPart); // Отправка AT команды //!!! ТЕКСТ СТРАНИЦЫ. НУЖНО ПРЕДУСМОТРЕТЬ response/data_buffer "НУЖНОЙ ДЛИНЫ"
while ( ((millis() - previous) < 15000) ){ //нужно добавить выход из цикла, когда прочитаны все данные. чтобы не зависать.
if ( GPRS.available() > 0 ) {
//Serial.println(avail, DEC);
// if there are data in the UART input buffer, reads it and checks for the asnwer
avail = GPRS.read();
//Serial.write(avail);
if ( stepP == 3 ){ // полезные данные закидываю в другой буфер
data_buffer[y] = avail;
y++;
}else{
response[x] = avail;
x++;
}
//парсинг ответа
if ( stepP == 0 ){
istr = strstr ( response + pars, firstPart); //"AT+HTTPREAD"
if ( istr != NULL ){
pars = (istr - response) + 11; // "AT+HTTPREAD"
stepP = 1;
}
} else if ( stepP == 1 ){
//Serial.write(avail);
istr = strstr ( response + pars , secondPart); //"+HTTPREAD:"
if ( istr != NULL ){
pars = (istr - response) + 10; // "+HTTPREAD:"
stepP = 2;
}
} else if ( stepP == 2 ){
//Serial.write(avail);
istr = strstr ( response + pars , "\r\n");
if ( istr != NULL ){
//*(response + pars) указывает на следующий символ после +HTTPREAD:
//и он может быть пробелом. нужно его пропустить
while ( *(response + pars) == ' ' )
pars++;
//Serial.println(" 2 - 3 ");
strncpy (DataLenRead, response + pars, istr - response - pars);
DataLenRead[istr - response - pars] = '\0'; // добавить в конец строки символ конца строки
//char test[40];
//sprintf(test, " *(response + pars) = %d , *(? -1) = %d, *istr = %d", *(response + pars), *(response + pars - 1), (int)*istr);
//Serial.println(test);
//Serial.print("DataLenRead = ");
//Serial.print(DataLenRead);
//Serial.println("DataLenRead end ");
pars = (istr - response) + 2; // это смещение на позицию за "\r\n" на начало полезных данных
//beginData = response + pars; //начало полезных данных
stepP = 3;
DataLenReadNumber = TextToInt(DataLenRead);
*lengthData = DataLenReadNumber;
if ( DataLenReadNumber == 0 ){
stepP = 4;
}
}
} else if ( stepP == 3 ){ //шаг считывания полезных данных
//Serial.println(" q3 ");
poleznieBytes++; // доделать : когда прочитано 0 байт
//Serial.println(DataLenReadNumber, DEC);
if ( poleznieBytes == DataLenReadNumber ){
stepP = 4; // после считывания полезных байт будет ожидать "OK\r\n"
//pars += DataLenReadNumber; //будет указывать на "OK\r\n"
//endData = response + pars - 1; //конец полезных данных
}
} else if ( stepP == 4 ){
//Serial.write(avail);
istr = strstr ( response + pars , thirdPart); //"OK\r\n"
if ( istr != NULL ){
answer = 0;
break; // всё прочитали . прерываем
}
}
///////////////
}
}
response[x] = '\0';
//Serial.println(response); // вывод всего пришедшего ответа
data_buffer[y] = '\0';
//char test[10];
//sprintf(test, "%u - %u", poleznieBytes, DataLenReadNumber);
Serial.println(data_buffer);
//Serial.println(test);
//Serial.println("length data_buffer = ");
//Serial.println(strlen( data_buffer ));
/*Serial.println(data_buffer[1]);
Serial.println(data_buffer[2]);
Serial.println(data_buffer[3]);*/
return answer;
}
// обработка большинства команд завершается на stepP == 1
uint8_t read_answer_HTTP_GPRS(const char * AtCommand, const char * expected_answer, char * DataLen){
unsigned long previous;
uint8_t x, answer;
int avail;
char * istr;
int pars = 0, stepP = 0;
char * cc, * ccEnd;
x = 0;
previous = millis();
size_t sz, sz_ea;
sz = strlen(AtCommand);
sz_ea = strlen(expected_answer);
answer = 1; // error
while( GPRS.available() > 0)
GPRS.read(); // Clean the input buffer
memset(response, '\0', response_size); // Initialize the string
GPRS.println(AtCommand); // Отправка AT команды
while ( ((millis() - previous) < 10000) ){ // !!! timeout нужно скидывать, когда получаю байты данных
if ( GPRS.available() > 0 ) {
avail = GPRS.read();
response[x] = avail;
x++;
//парсинг ответа
if ( stepP == 0 ){
istr = strstr ( response + pars, AtCommand);
if ( istr != NULL ){
//Serial.println(" 0 \n");
pars = (istr - response) + sz;
stepP = 1;
}
} else if ( stepP == 1 ){
istr = strstr ( response + pars , "OK\r\n");
if ( istr != NULL ){
//Serial.println(" 1 \n");
answer = 0;
if (sz_ea == 0){ //передана пустая строка в expected_answer (в этой команде ждем ОК и завершаем обарботку; )
break;
}
// сюда пока попадает только, если отправлена команда "AT+HTTPACTION=0", требующая доп обработки
pars = (istr - response) + 4;
stepP = 2;
//Serial.println(" 1-1 \n");
continue;
}
istr = strstr ( response + pars , "ERROR\r\n");
if ( istr != NULL ){
break;
}
}else if ( stepP == 2 ){
//Serial.write(avail); // например, +HTTPACTION: 0,606,0 // +HTTPACTION: 0,200,175
istr = strstr ( response + pars, expected_answer);
if ( istr != NULL ){
//Serial.println(" 2 \n");
pars = (istr - response) + sz_ea + 1; // пропускаем запятую. встаем на начало длины полученных данных
cc = response + pars; // cc - начало длины данных
stepP = 3;
}
}else if ( stepP == 3 ){
ccEnd = strstr(cc, "\r\n"); // конец
if ( ccEnd != NULL ){
//Serial.println(" 3 \n");
//можно проверить на NULL
strncpy (DataLen, cc, ccEnd - cc);
DataLen[ccEnd - cc] = '\0'; // добавить в конец строки символ конца строки
//Serial.println(DataLen); // тут полученный размер (строка) который затем можно использовать в HTTPREAD
break;
}
}
}
}
response[x] = '\0';
//Serial.println(response); // вывод всего пришедшего ответа
return answer;
} // read_answer_HTTP_GPRS()
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
uint8_t get_SMSdata_http(void){
uint8_t answer = 0;
char DataLen[15];
unsigned int lengthData;
int c;
// баланс:
/*Serial.println("Отправка: AT+CUSD=1,\"*100#\"");
GPRS.println("AT+CUSD=1,\"*100#\""); // Отправка AT команды
delay(2000);
*/
Serial.println("=== Отправка: AT+HTTPINIT\n");
answer = read_answer_HTTP_GPRS("AT+HTTPINIT", "", NULL);
if (answer != 0)
return answer;
//goto Ext1;
//00/////////SSL - эта версия устарела. сейчаc всюду TLS. Не нашёл ресурсов с ssl - не протестировал до конца///////
/*
Serial.println("=== Отправка: AT+HTTPSSL=1\n");
answer = read_answer_HTTP_GPRS("AT+HTTPSSL=1", "", NULL);
if (answer != 0){
//Serial.println(response); // вывод всего пришедшего ответа
return answer;
}
Serial.println("=== Отправка: AT+HTTPSSL=1 - OK \n");
*/
/* while( GPRS.available() > 0)
Serial.write(GPRS.read()); // Clean the input buffer
Serial.println("Отправка: AT+HTTPSSL?");
GPRS.println("AT+HTTPSSL?"); // Отправка AT команды
delay(2000);
x = 0;
answer = 0;
while (GPRS.available() != 0){
// if there are data in the UART input buffer, reads it and checks for the asnwer
response[x] = GPRS.read();
x++;
}
response[x] = '\0';
Serial.println(response);
// check if the desired answer is in the response of the module
if (strstr(response, "OK") != NULL){
answer = 1;
}
//if (answer == 0)
//goto Ext1;
*/
//77////////////////
Serial.println("Отправка: AT+HTTPPARA=\"CID\",1");
answer = read_answer_HTTP_GPRS("AT+HTTPPARA=\"CID\",1", "", NULL);
if (answer != 0)
return answer;
//goto Ext1;
//88////////////////
Serial.println("Отправка: AT+HTTPPARA=\"URL\",\"http://mirossa.ru/q756dd/fcl01/7a888tyt.php\"");
answer = read_answer_HTTP_GPRS("AT+HTTPPARA=\"URL\",\"http://mirossa.ru/q756dd/fcl01/7a888tyt.php?l=12&p=12\"", "", NULL);
if (answer != 0){
//Serial.println(response);
return answer;
//goto Ext1;
}
//88////////// USER AGENT //////
Serial.println("Отправка: USER AGENT");
answer = read_answer_HTTP_GPRS("AT+HTTPPARA=\"UA\",\"Go-http-clientQ/1.1\"", "", NULL); // иначе в USER-AGENT будет "SIMCOM_MODULE"
if (answer != 0){
//Serial.println("USER AGENT error");
return answer;
//goto Ext1;
}
//10////////////////////////////
Serial.println("Отправка: AT+HTTPACTION=0");
answer = read_answer_HTTP_GPRS("AT+HTTPACTION=0", "+HTTPACTION: 0,200", DataLen); // нужно парсить! В sim900 так "+HTTPACTION:0,200",
// в sim800c так "+HTTPACTION: 0,200" (с пробелом)
if (answer != 0){ //error
//Serial.println(response);
return answer;
//goto Ext1;
}
//отладка
Serial.println(DataLen);
//11////////// AT+HTTPHEAD читаем заголовки http-ответа ////////////////////
Serial.println("Отправка: AT+HTTPHEAD");
while( GPRS.available() > 0)
GPRS.read(); // Clean the input buffer
GPRS.println("AT+HTTPHEAD"); // Отправка AT команды
previous = millis();
while ( ((millis() - previous) < 5000) ){ // !!! timeout нужно скидывать, когда получаю байты данных
if ( GPRS.available() > 0 ) {
Serial.write(GPRS.read()); // Теряются последние несколько символов. Это было из-за того, что скорость GPRS была
// установлена больше (19200), чем скорость обмена с монитором порта (9600).
}
}
Serial.println("конец AT+HTTPHEAD");
// пример ответа:
/* AT+HTTPHEAD
+HTTPHEAD: 154
http/1.1 200 ok
server: nginx
date: sun, 18 aug 2019 15:01:27 gmt
content-type: text/html; charset=utf-8
content-length: 9
connection: keep-alive
OK
*/
//////////////////////////////////
//Serial.println("Отправка: AT+HTTPREAD=0,175");
Serial.println("=== Отправка: AT+HTTPREAD");
//GPRS.println("AT+HTTPREAD=0,175");
answer = read_answer_httpread("AT+HTTPREAD", "+HTTPREAD:", "OK\r\n", &lengthData );
if (answer != 0) //error
return answer;
//goto Ext1;
Serial.println("=== Успешно: AT+HTTPREAD");
//отладка
Serial.print("=== Получено полезных байт: ");
Serial.println(lengthData, DEC);
//Serial.print("=== Начало полезных байт");
//for (c = 0; c < lengthData; c++ )
//Serial.write( data_buffer[c] );
//Serial.println("=== Конец полезных байт");
//отладка
//12//////////////////////////////////////
//////////////////////////////////////////
//HTTPTERM:
Serial.println("Отправка: AT+HTTPTERM");
//answer = read_answer_HTTP_GPRS("AT+HTTPTERM");
answer = read_answer_HTTP_GPRS("AT+HTTPTERM", "", NULL);
if (answer != 0)
return answer;
//goto Ext1;
/////////////
return answer;
} // get_SMSdata_http()
////////////////////////// для MTS //////////////////////////////////////////////////////////////////////////////////////////////
uint8_t start_GPRS(void){
uint8_t answer = 0;
//11111111////////////
answer = read_answer_HTTP_GPRS("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"", "", NULL);
if (answer != 0)
return answer;
//goto Ext1;
//222222222/////////
answer = read_answer_HTTP_GPRS("AT+SAPBR=3,1,\"APN\",\"internet.mts.ru\"", "", NULL);
if (answer != 0)
return answer;
//goto Ext1;
//33333333/////////
answer = read_answer_HTTP_GPRS("AT+SAPBR=3,1,\"USER\",\"mts\"", "", NULL);
if (answer != 0)
return answer;
//goto Ext1;
//4444////////////////////
answer = read_answer_HTTP_GPRS("AT+SAPBR=3,1,\"PWD\",\"mts\"", "", NULL);
if (answer != 0)
return answer;
//goto Ext1;
//555/////////////////
answer = read_answer_HTTP_GPRS("AT+SAPBR=1,1", "", NULL);
if (answer != 0)
return answer;
//goto Ext1;
//666///////////////
return answer;
} // start_GPRS
// программное включение питания
void power_on()
{
uint8_t answer;
pinMode(onModulePin,OUTPUT);
// checks if the module is started
digitalWrite(onModulePin,LOW);
delay(1000);
digitalWrite(onModulePin,HIGH);
delay(2000);
digitalWrite(onModulePin,LOW);
delay(3000);
/* answer = read_answer_HTTP_GPRS("AT", "", NULL);
if (answer != 0)
{
digitalWrite(onModulePin,LOW);
delay(1000);
digitalWrite(onModulePin,HIGH);
delay(2000);
digitalWrite(onModulePin,LOW);
delay(3000);
digitalWrite(onModulePin,HIGH);
delay(3000);
digitalWrite(onModulePin,LOW);
// время ожидания ответа
while(answer != 0)
{
// Send AT every n seconds and wait for the answer
answer = read_answer_HTTP_GPRS("AT", "", NULL);
}
}
*/
}
Begin HTTP request.
=== Отправка: AT+HTTPINIT
Отправка: AT+HTTPPARA="CID",1
Отправка: AT+HTTPPARA="URL","http://mirossa.ru/q756dd/fcl01/7a888tyt.php"
Отправка: USER AGENT
Отправка: AT+HTTPACTION=0
178
Отправка: AT+HTTPHEAD
AT+HTTPHEAD
+HTTPHEAD: 179
http/1.1 200 ok
server: nginx
date: fri, 04 oct 2019 23:12:07 gmt
content-type: text/html; charset=utf-8
content-length: 178
connection: keep-alive
vary: accept-encoding
OK
конец AT+HTTPHEAD
=== Отправка: AT+HTTPREAD
<html><body>
<p>hello, . machine! and test testovich223?</p>
<p>second floor.</p>
<p>third machine.</p>
<p>Captan</p>
<p>sketch 1313</p>
<p>Next page is 57.</p>
</body></html>
=== Успешно: AT+HTTPREAD
=== Получено полезных байт: 178
Отправка: AT+HTTPTERM
AT+SAPBR=0,1
OK
https://alex-exe.ru/radio/wireless/gsm-sim900-gprs/
http://ak.ale31.ru/работа-c-at-командами-и-gprs-на-arduino/
https://www.raviyp.com/embedded/194-sim900-gprs-http-at-commands?start=1
Прошивка hex-файлов в Arduino
https://acdc.foxylab.com/avrdude
http://mega-avr.com.ua/programma-sinaprog-2-1-1-rus/
//запуск из консоли
C:\avrdude\avrdude.exe -C avrdude.conf -c arduino -P com3 -p m328p -U flash:w:"C:\avrdude\SoftwareSerialExample_PSP.ino.standard.hex":a -q
Комментарии