#1 2017-08-18 20:24:38

Elmirus3
Участник
Из Одесса
Зарегистрирован: 2017-07-29
Сообщений: 17

Парсинг сообщений из порта

Добрый вечер, подскажите пожалуйста как правильно парсить координаты NMEA, или как изменить формат координат, которые извлекают уже существующие библиотеки

Например, нужно соорудить такую строчку: 130402213013,+380680000000,GPRMC,173013.000,A,6146.4979,N,03421.2399,E,1.92,21.48,020413,,,A*5B,F,, imei:867567020000000,00,-16.4,F:3.73V,0,139,49646,250,99,1478,68A7\n\r

От GPS модуля приходит такая вот штуковина: $GPRMC,214603.000,A,4634.54557,N,03047.50473,E,0.00,0.00,040617,,,A*6E

То есть мне нужно извлечь координаты в таком формате 6146.4979,N,03421.2399,E и вставить их в нужную мне строку, которую описывал первой, например присвою их переменным и уже там буду играться как умею, ==НО== парсить, я совсем не умею и когда использовал библиотеку TinyGPS - координаты мне приходили в таком формате: LAT=46.576423 LON=30.788080, то есть проблема у меня в том как при помощи библиотеки или куска кода для парсинга

из этого - 46.576423 30.788080 сделать это вот 4634.54557 03047.50473 ??? Бо и точки не там стоят да и количество цифр совсем не то в каком формате принимает сервер.

Сервер принимает в таком формате 4634.54557 03047.50473, а в таком 46.576423 30.788080 не принимает, помогите пожалуйста!

#2 2017-08-18 21:05:51

Elmirus3
Участник
Из Одесса
Зарегистрирован: 2017-07-29
Сообщений: 17

Re: Парсинг сообщений из порта

отправляю данные вот такой функцией:

//разбиваю одну строку на несколько, что б в функции вместо тестового cord применять message где и должны хранится координаты
const char resource[] = "130402213013,+380688260000,GPRMC,175135.000,A,";
const char cord[] = "6146.4979,N,03421.2399,E";   //вот такие координаты может принять сервер
const char stat[] = ",1.92,21.48,100817,,,A*5B,F,, imei:867567021260000,00,-16.4,F:3.73V,0,139,49646,250,99,1478,68A7\n\r";

void TcpGprsMessage(String message){

     sendData("AT+CREG?",3000,DEBUG);     
     sendData("AT+CGATT=1",1000,DEBUG);
     sendData("AT+CGDCONT=1,\"IP\",\"www.ab.kyivstar.net\"",1000,DEBUG);
     sendData("AT+CGACT=1,1",1000,DEBUG);
     sendData("AT+CIPSTART=\"TCP\",\"88.198.136.232\",10001",3000,DEBUG);
     sendData("AT+CIPSEND=80",1000,DEBUG);
     sendData(String("GET ") + resource + cord + stat, 2000,DEBUG);
     delay(1000);
     sendData("AT+CIPCLOSE",2000,DEBUG);     //Close TCP
     delay(100);


}


Сам код:

#define DEBUG true

char byteGPS=-1;
char linea[300] = "";
char comandoGPR[7] = "$GPRMC";
int cont=0;
int bien=0;
int conta=0;
int indices[13];

int GPS_time=30;                        // When the board gets the 30 times location information successfully and the location information will be send by sms.      
String target_phone = "+380634250000"; // Your phone number,be careful need to add a country code before the cellphone number

String GPS_position="";
int GPS_position_count=0;


const char resource[] = "130402213013,+380688260000,GPRMC,175135.000,A,";
const char cord[] = "6146.4979,N,03421.2399,E";
const char stat[] = ",1.92,21.48,100817,,,A*5B,F,, imei:867567021260000,00,-16.4,F:3.73V,0,139,49646,250,99,1478,68A7\n\r";


void setup()
{
  Serial.begin(115200);
  Serial1.begin(115200);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(8,OUTPUT);
  digitalWrite(5, HIGH); 
  digitalWrite(4, LOW); 
  digitalWrite(8, LOW); 
  delay(2000);
  digitalWrite(8, HIGH); 
  delay(3000);       
  digitalWrite(8, LOW);
  Serial.println("A7 Power ON!");
  sendData("AT+GPS=0",3000,DEBUG);     //Close GPS
  for(int i=0;i<2;i++){                //Make sure the GPS has been turned on
    sendData("AT+GPSRD=1",1000,DEBUG);
    Serial1.println("AT+GPS=1");
  }
  Serial.println("*********************************************************");
  Serial.println("**If don`t display 'GPS positioning....',please reboot.**");
  Serial.println("*********************************************************");
}

void loop()
{
    testgps();
}

void testgps(){
  while(Serial1.available()){
   byteGPS=Serial1.read();  
  // Read a byte of the serial port
   if (byteGPS == -1) {       
    // See if the port is empty yet
   } 
   else {
     // note: there is a potential buffer overflow here!
     linea[conta]=byteGPS;        // If there is serial port data, it is put in the buffer
     conta++;                      
     //Serial.print(byteGPS);    // '//',есди удалить то будут отправлятся все данные 
     if (byteGPS==13){
      // If the received byte is = to 13, end of transmission
      // note: the actual end of transmission is <CR><LF> (i.e. 0x13 0x10)
      cont=0;
      bien=0;
      // The following for loop starts at 1, because this code is clowny and the first byte is the <LF> (0x10) from the previous transmission.
       for (int i=1;i<7;i++){     // Verifies if the received command starts with $GPR
         if (linea[i]==comandoGPR[i-1]){
           bien++;
         }
       }
       if(bien==6){ 
        // If yes, continue and process the data
        //Data Partitioning
         for (int i=0;i<300;i++){
           if (linea[i]==','){    // check for the position of the  "," separator
             // note: again, there is a potential buffer overflow here!
             indices[cont]=i;
             cont++;
           }
           if (linea[i]=='*'){    // ... and the "*"
             indices[12]=i;
             cont++;
           }
         }
         //panel data, for example:Direction (E/W):Longitude-Direction(N/S):Latitude<--->E:11350.51872-N:2236.40687        
         for(int i=5;i>1;i--){
           for (int j=indices[i];j<(indices[i+1]-1);j++){
             GPS_position+=linea[j+1];
           }
           if((i==5)||(i==3)){
             GPS_position+=":";  
           }else if(i==4){
             GPS_position+="-";   
           }
         }
         //If the return ":-:", it means empty data, continue positioning 
         if(GPS_position==":-:"){
          Serial.println("GPS positioning....");
         }else{
            Serial.println(GPS_position);
            GPS_position_count++;
            //When GPS_position_count is equivalent to GPS_time, stop positioning and start to send sms messages
            if(GPS_position_count==GPS_time){
            GPS_position_count=0;          //Reset count
            sendData("AT+GPS=0",1000,DEBUG);
            delay(1000); 
            //SendTextMessage(GPS_position); //SMS
            TcpGprsMessage(GPS_position); //Internet
            sendData("AT+GPS=1",1000,DEBUG); 
           }
                  
         }
       }
       GPS_position="";
       conta=0;                    // Reset the buffer
       for (int i=0;i<300;i++){    //  
       linea[i]=' ';             
       }                
     }
   }  
   }
}

void TcpGprsMessage(String message){

     sendData("AT+CREG?",3000,DEBUG);     
     sendData("AT+CGATT=1",1000,DEBUG);
     sendData("AT+CGDCONT=1,\"IP\",\"www.ab.kyivstar.net\"",1000,DEBUG);
     sendData("AT+CGACT=1,1",1000,DEBUG);
     sendData("AT+CIPSTART=\"TCP\",\"88.198.136.232\",10001",3000,DEBUG);
     sendData("AT+CIPSEND=80",1000,DEBUG);
     sendData(String("GET ") + resource + message + stat, 2000,DEBUG); 
     delay(1000);
     sendData("AT+CIPCLOSE",2000,DEBUG);     //Close TCP
     delay(100);

     //sendData(String("GET ") + resource + imei + message,2000,DEBUG); 
}

void SendTextMessage(String message)
{ 
  sendData("AT+CMGF=1",5000,DEBUG);            //Set the SMS in text mode
  delay(100);
  sendData("AT+CMGS="+target_phone,2000,DEBUG);//send sms message to the cellphone , be careful need to add a country code before the cellphone number
  delay(100);
  sendData(message,2000,DEBUG);                //the content of the message
  delay(100);
  Serial1.println((char)26);                  //the ASCII code of the ctrl+z is 26
  delay(100);
  sendData("",1000,DEBUG);                     //Clear serial data
  delay(100);
}

void sendData(String command, const int timeout, boolean debug)
{
    String response = "";    
    Serial1.println(command); 
    long int time = millis();   
    while( (time+timeout) > millis()){
      while(Serial1.available()){       
        response += (char)Serial1.read(); 
      }  
    }    
    if(debug){
      Serial.print(response);
    }    
}

#3 2017-08-19 12:24:28

Nefreemen
Участник
Из Киев
Зарегистрирован: 2015-12-19
Сообщений: 540

Re: Парсинг сообщений из порта

А я вот Вас не пойму.
"От GPS модуля приходит такая вот штуковина: $GPRMC,214603.000,A,4634.54557,N,03047.50473,E,0.00,0.00,040617,,,A*6E"
Вам надо:
"130402213013,+380680000000,GPRMC,173013.000,A,6146.4979,N,03421.2399,E,1.92,21.48,020413,,,A*5B,F,, imei:867567020000000,00,-16.4,F:3.73V,0,139,49646,250,99,1478,68A7\n\r"

Скажите что тут парсить? У Вас от модуля GPS уже приходит нужное, за исключением $ smile .

#4 2017-08-19 13:12:43

Elmirus3
Участник
Из Одесса
Зарегистрирован: 2017-07-29
Сообщений: 17

Re: Парсинг сообщений из порта

То есть приходит в монитор порта вот такая шняга и из 2й строки $GPRMC нужно оставить хотя бы выделенное красным:

Screenshot_1.png

2я строка как раз нужного формата, но как убрать в ней по последней цифре в долготе и широте?

Получается, левые 2 цифры, при наличии которых сервер отказывается показывать местоположение:

Screenshot_2.png




Вот кусок моего сооружения:
20170819_132735.jpg

Редактировался Elmirus3 (2017-08-19 13:33:22)

#5 2017-08-19 15:19:33

NoName
Customer
Из Київ
Зарегистрирован: 2014-07-08
Сообщений: 1,220

Re: Парсинг сообщений из порта

http://www.rapidtables.com/convert/number/degrees-to-degrees-minutes-seconds.htm
Example
Convert 30.263888889° angle to degrees,minutes,seconds:
d = integer(30.263888889°) = 30°
m = integer((dd - d) × 60) = 15'
s = (dd - d - m/60) × 3600 = 50"
So
30.263888889° = 30° 15' 50"

#6 2017-08-19 17:52:11

Nefreemen
Участник
Из Киев
Зарегистрирован: 2015-12-19
Сообщений: 540

Re: Парсинг сообщений из порта

Если так не подходит (в лоб smile ) поскольку лишняя цифра. Что бы не парсить (это не совсем простая задача для Вас) то используйте ту библиотеку о которой Вы упоминали, я так понял что речь идет о https://github.com/mikalhart/TinyGPSPlus.
Я мельком глянул, насколько понял то она позволяет получить (как свойство объекта ) любую величину GPS данных. Если она Вам дает не там запятую то умножьте на 100  smile .
Вряд ли здесь кто то захочет писать Вам парсинг (если у него готового нет)  smile .

Редактировался Nefreemen (2017-08-19 17:54:56)

#7 2017-08-19 18:31:26

NoName
Customer
Из Київ
Зарегистрирован: 2014-07-08
Сообщений: 1,220

Re: Парсинг сообщений из порта

Nefreemen они сразу переводят в градусы при парсинге
DDMM.SSSS  > DD.DDDDDDDDDD

    case COMBINE(GPS_SENTENCE_GPRMC, 3): // Latitude
    case COMBINE(GPS_SENTENCE_GPGGA, 2):
      location.setLatitude(term);
      break;
    case COMBINE(GPS_SENTENCE_GPRMC, 4): // N/S
    case COMBINE(GPS_SENTENCE_GPGGA, 3):
      location.rawNewLatData.negative = term[0] == 'S';
      break;
    case COMBINE(GPS_SENTENCE_GPRMC, 5): // Longitude
    case COMBINE(GPS_SENTENCE_GPGGA, 4):
      location.setLongitude(term);
      break;

умножать  на 100 это лишнее )

#8 2017-08-19 18:56:16

NoName
Customer
Из Київ
Зарегистрирован: 2014-07-08
Сообщений: 1,220

Re: Парсинг сообщений из порта

"Вряд ли здесь кто то захочет писать Вам парсинг (если у него готового нет)  smile ."
Я Одессе по старой памяти сделаю  )
как упоительные были ночные брожения с пивзавода  по проспекту Шевченко ))))
хотя вчера так ругался !!! когда нахренатор ( испоганили таки "товарищи" с mail.ru  maps.me  mad ) через  центр пустил вместо того что б  через Авангард рвануть. но ет не по делу )

Elmirus3 вам нужно немного поправить библиотеку или поискать другую.

change  на быструю руку без проверки multiplier .

// static
// Parse degrees in that funny NMEA format DDMM.MMMM
void TinyGPSPlus::parseDegrees(const char *term, RawDegrees &deg)
{
  uint32_t leftOfDecimal = (uint32_t)atol(term);
  // uint16_t minutes = (uint16_t)(leftOfDecimal % 100);
  // uint32_t multiplier = 10000000UL;
  uint32_t multiplier = 100000UL;
  // uint32_t tenMillionthsOfMinutes = minutes * multiplier;
  uint32_t tenMillionthsOfMinutes = 0;

  // deg.deg = (int16_t)(leftOfDecimal / 100);
     deg.deg = leftOfDecimal;


	 while (isdigit(*term))
    ++term;

  if (*term == '.')
    while (isdigit(*++term))
    {
      multiplier /= 10;
      tenMillionthsOfMinutes += (*term - '0') * multiplier;
    }

//  deg.billionths = (5 * tenMillionthsOfMinutes + 1) / 3;
  deg.billionths = ( tenMillionthsOfMinutes );

  deg.negative = false;
}

эта либа под GNU Lesser General Public License (LGPL)   не забывайте )

#9 2017-08-19 19:13:20

Elmirus3
Участник
Из Одесса
Зарегистрирован: 2017-07-29
Сообщений: 17

Re: Парсинг сообщений из порта

NoName пишет:

"Вряд ли здесь кто то захочет писать Вам парсинг (если у него готового нет)  smile ."
Я Одессе по старой памяти сделаю  )
как упоительные были ночные брожения с пивзавода  по проспекту Шевченко ))))
хотя вчера так ругался !!! когда нахренатор ( испоганили таки "товарищи" с mail.ru  maps.me  mad ) через  центр пустил вместо того что б  через Авангард рвануть. но ет не по делу )


Да без майла жостко с пробками. Я в прошлом месяце в Киеве с гуглкартами потерялся((

За либу спасибо, ее призывать так как и tinygps++?)

Редактировался Elmirus3 (2017-08-19 19:14:35)

#10 2017-08-19 19:17:16

NoName
Customer
Из Київ
Зарегистрирован: 2014-07-08
Сообщений: 1,220

Re: Парсинг сообщений из порта

Elmirus3 если забить на пробки то "to GIS" но пару разпод знак пускал.
скиньте в личку  viber / скайп я обьясню

#11 2017-08-19 20:31:10

Elmirus3
Участник
Из Одесса
Зарегистрирован: 2017-07-29
Сообщений: 17

Re: Парсинг сообщений из порта

NoName пишет:

Elmirus3 если забить на пробки то "to GIS" но пару разпод знак пускал.
скиньте в личку  viber / скайп я обьясню

0634259229 можно и так)

#12 2017-08-20 07:44:50

Вячеслав Азаров
Участник
Из Запорожье
Зарегистрирован: 2017-05-25
Сообщений: 406

Re: Парсинг сообщений из порта

Для парсинга вы можете использовать классический scanf и его модификации, просто и эффективно.

#13 2017-08-20 09:31:20

NoName
Customer
Из Київ
Зарегистрирован: 2014-07-08
Сообщений: 1,220

Re: Парсинг сообщений из порта

нашел...
http://forum.arduino.ua/viewtopic.php?pid=20828#p20828
точно что то пробовал такое делать )
парсер простой,

Вячеслав Азаров  сколько добавляет кода такая либа? никогда даже не пробовал подключать, всегда места не хватает (

#14 2017-08-20 12:43:33

qwone
Участник
Зарегистрирован: 2016-07-25
Сообщений: 104

Re: Парсинг сообщений из порта

В общем для решения можно пойти тремя путями.
1- использовать указатели
2- использовать встроенные средства языка Си
3- использовать String
Ну и по мне еще лучше написать свой String под решение этой задачи. Но мне это зачем. Я же не ТС.
ПС: А памяти хватит, если прямыми руками писать код.

#15 2017-08-20 22:46:39

Elmirus3
Участник
Из Одесса
Зарегистрирован: 2017-07-29
Сообщений: 17

Re: Парсинг сообщений из порта

Получилось получить 03047.50473 то, что в принципе и нужно, но опять таки как убрать тут последнюю цифру?

#include "string.h"


char s[] ="$GPRMC,214603.000,A,4634.54557,N,03047.50473,E,0.00,0.00,040617,,,A*6E";
char * p;
int a = 0;

void setup(void) {
Serial.begin(115200);

p = strtok (s,",");

  for(int i=0; p != NULL; i++)
  {
      a++;
      if (a == 5) {         // тут указываю число расчлененной части S
        Serial.println(p);
      }
  
    p = strtok (NULL, ",");
  }
    
}

void loop(void) {}

#16 2017-08-21 08:44:07

Вячеслав Азаров
Участник
Из Запорожье
Зарегистрирован: 2017-05-25
Сообщений: 406

Re: Парсинг сообщений из порта

NoName пишет:

нашел...
http://forum.arduino.ua/viewtopic.php?pid=20828#p20828
точно что то пробовал такое делать )
парсер простой,

Вячеслав Азаров  сколько добавляет кода такая либа? никогда даже не пробовал подключать, всегда места не хватает (

Да, stdio громоздкая штука. Но если нужно делать разбор текста или шаблонную печать то это того стоит. Для AVR она упрощенная. Ориентировочно sscanf 1.8K, sprintf 1.5K.

#17 2017-08-21 18:51:21

Elmirus3
Участник
Из Одесса
Зарегистрирован: 2017-07-29
Сообщений: 17

Re: Парсинг сообщений из порта

Как убрать последние 2 символа в 4634.54557,  (запятая и семерка), чтоб получилось  4634.5455 ?

#include "string.h"


char *s = "$GPRMC,214603.000,A,4634.54557,N,03047.50473,E,0.00,0.00,040617,,,A*6E";
char *p;

void setup(void) {
Serial.begin(115200);

p = strchr(s, 'A') + 2; // тут начало от А +2 символа
p = strtok(p, "N");     // тут после , обрезает лишнее но как сделать типо -2 ?

    Serial.println(p);
   
}

void loop(void) {}

#18 2017-08-21 19:49:49

NoName
Customer
Из Київ
Зарегистрирован: 2014-07-08
Сообщений: 1,220

Re: Парсинг сообщений из порта

p[9] = '\0';
но это через задницу решение )

#19 2017-08-21 21:01:20

Elmirus3
Участник
Из Одесса
Зарегистрирован: 2017-07-29
Сообщений: 17

Re: Парсинг сообщений из порта

о, чотенько. А чего через жопу?

#20 2017-08-22 10:29:19

Elmirus3
Участник
Из Одесса
Зарегистрирован: 2017-07-29
Сообщений: 17

Re: Парсинг сообщений из порта

А как можно вытащить строку выделенную красным начинающуюся с GPRMC для ее дальнейшего парсинга?
Screenshot_1.png

Редактировался Elmirus3 (2017-08-22 10:30:49)

Быстрое сообщение

Введите сообщение и нажмите Отправить

Подвал раздела