Thursday, 29 December 2011

Arduino Live GPS Tracker - HOWTO

As promised earlier, this post is a complete HOWTO with code on how to use an Antrax GSM/GPRS/GPS Shield with an Arduino for Live Position Tracking.  Note that I am using the Rev 2 of the Antrax GSM/GPRS/GPS shield which has the Telit GE864-QUAD GSM Module controlled via Serial and the Origin ORG1318 GPS Module controlled via SPI interface. Antrax has since then launched a Rev 6 Version which uses the Telit GE865-QUAD GSM module and the Fastrax UP501 GPS module.

Objective
We will try to get the GPS position and send the data to an HTTP Server to store it which can then be used for various purposes one of which is plotting the current position on Google Maps.

SPI Wiring
The SPI port on the Arduino Mega is at pin 50-53 as opposed to 10-13 on the Arduino Uno. Hence we need to do some soldering to connect the corresponding SPI pins from the shield to the right ports. Antrax provides all the necessary tidbits to do this. The rework instructions can be obtained from here. Be careful while soldering. If you do not know how to do it get the help of someone who knows.

The rework documentation shows the pins 10-13 bent outside. However, in my case, it's bent inwards to save space in case I decide to box the final product.

Now mount the shield over the Arduino Mega/Uno making sure all the pins are correctly aligned. Place in the SIM card with the notched edge facing outwards and the logo upwards. The final setup should look like this.
My Kit with the Vodafone Sim inserted. The White cable is the SPI connection.
Software
I used the latest version of Arduino IDE available(1.0). Two changes I noticed with this version are that WProgam.h is replaced by Arduino.h and Serial.print(byte, BYTE) has been replaced with Serial.Write(byte).

Make sure you have selected the right board in Tools>Board. For me it is the "Arduino Mega 2560 or Mega ADK". Also ensure you have selected the right Serial Port in Tools>Serial Port. You can identify your Serial Port in Linux by tailing the /var/log/messages when connecting the Arduino via USB.

Arduino Code
Projects in Arduino are called Sketches. Our Sketch will include 3 files. Arduino IDE does not allow adding separate files from the IDE, so it is advisable to create these outside of the IDE and then open the .ino file with Arduino which will open all the three files. Arduino also requires that the ino file and the directory containing it should have the same basename. So, if your ino file is called GSM.ino the folder which holds this file should be called GSM.

For my example the folder is called GSM_HTTP. Use a text editor for copying the code into the individual files.

Following is the code for the GSM_HTTP.ino file:

/* Filename: GSM_HTTP.ino
 * Author: Sam Albuquerque
 * Description: Sketch to periodically upload GPS data over GPRS
 *              to remote Server via HTTP connection
 * used with Arduino Mega
 */

#include "GM862.h"
#include <SPI.h>
#define GSMPin 7    //Pin 7 is the Power Pin for our shield
#define baud 9600

//Class to handle the GPS part of the shield.
class GPS {
  public:
    GPS(int ledPin);
    char coordinate[23];  //DDMM.SSSSN,DDDMM.SSSSW
    boolean gpsState;  
    void getGPS();
    long time;            //HHMMSS  UTC time
  private:
    int gpsLed;           //PIN Number for GPS LED
};


GPS::GPS(int ledPin){
  gpsLed=ledPin;
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin,LOW);
  gpsState = false;
  time=0;
}

void GPS::getGPS(){
  char gps_data_buffer[7];
  char command_result;
  byte high_Byte;
  int i;
  byte GPGGA;

  SPI.begin();
  SPI.setDataMode((0<<CPOL) | (1 << CPHA) |(1<<SPI2X));

  delay(1000);

  GPGGA=0;
  i=0;
  do {
    digitalWrite(SS, LOW);
   
    if(high_Byte == 1){
      command_result=SPI.transfer(0xA7);
      high_Byte = 0;
    } else {
      command_result=SPI.transfer(0xB4);
      high_Byte = 1;
    }
    for(int index=0; index<6; index++){
      gps_data_buffer[index] = gps_data_buffer[index + 1];
    }
    gps_data_buffer[6] = command_result;

    if((gps_data_buffer[0] == '$') && (gps_data_buffer[1] == 'G') && (gps_data_buffer[2] == 'P') && (gps_data_buffer[3] == 'G') && (gps_data_buffer[4] =='G') && (gps_data_buffer[5] == 'A')) {
      GPGGA = 1;         //We found a $GPGGA Sentence
    }

    if((GPGGA == 1) && (i < 80 ))
    {

      if(gps_data_buffer[0] == 0x0D) { //Sentence ends with 0x0D(Return) Character
        i = 80;
        GPGGA = 0;
      } else {
        if(i>=7 && i<13){   //Characters 7-12 are UTC Time String
          time = ((time*10) + (int(gps_data_buffer[0]) - 48))%1000000;
        }
        if(i>=18 && i<27){  //Characters 18-26 are Latitude
         coordinate[i-18]=gps_data_buffer[0];
        }
        if(i==28) coordinate[9]=gps_data_buffer[0];  //Character 28 is either N or S Hemisphere
        if(i==29) coordinate[10]=',';       
        if(i>=30 && i<40){  //Characters 30 to 39 are Longitude
         coordinate[i-19]=gps_data_buffer[0];
        }        
        if(i==41) coordinate[21]=gps_data_buffer[0];  

        i++;                //Character 41 is either E or W Hemisphere
        }
    }

    digitalWrite(SS, HIGH);
  } while (i<80);
  if((coordinate[0]) == ','){
      gpsState=false;          //GPS Position Not Found
  } else {
    gpsState=true;            //GPS Position Found
    coordinate[22]='\0';      //Valid String ends with Null Character.
  }
  digitalWrite(gpsLed, gpsState);
  return;
}

GPS gps(9);                          //Pin 9 is used to control the GPS LED.

char PIN[5] = "0000";                // replace this with your SIM PIN
GM862 modem(&Serial, GSMPin, PIN);   // Our shield communicates over default Serial
char cmd;                            // command read from terminal
long lastTime=0;

void setup() {          
  Serial.begin(9600);
  Serial.println("GM862 monitor");
  modem.switchOn();                   // switch the modem on
  delay(4000);                        // wait for the modem to boot
  modem.init();                       // initialize the GSM part of Module
  modem.version();                    // request modem version info
  while (!modem.isRegistered()) {
    delay(1000);
    modem.checkNetwork();             // check the network availability
  }

}


void requestHTTP() {
  char buf[100];
  byte i = 0;
  modem.initGPRS();                   // setup of GPRS context
  modem.enableGPRS();                 // switch GPRS on
  modem.openHTTP("IP.AD.RE.SS");    //  Replace IP.AD.RE.SS with your target's IP

                                    //   or domain name
  modem.send("GET /location.php?time=");  //Connects to location.php on Server
  Serial.print(gps.time);                 //Passes UTC Time
  modem.send("&loc=");                    // and
  modem.send(gps.coordinate);             //GPS coordinates
  modem.send(" HTTP/1.1\r\n");          //Completes HTTP GET Request
  modem.send("HOST: IP.AD.RE.SS \r\n");   //write on the socket
  modem.send("\r\n");                     //Completes the HTTP Connection
  delay(1000);
  while (i++ < 10) {                  // try to read for 10s
    modem.receive(buf);               // read from the socket, timeout 1s
    if (strlen(buf) > 0) {            // we received something
      i--;                            // reset the timeout
    }
  }
  modem.disableGPRS();                // switch GPRS off
}


void loop() {
    gps.getGPS();
     if(gps.gpsState==true){
       if(gps.time-lastTime > 100){       //if posted more than a minute ago
          requestHTTP();                  // do a HTTP request
          lastTime=gps.time;              //Store the last update time
          delay(5000);
       }
     } else {
       Serial.println("0");              //Prints 0 if GPS fix not received.
     }
}


The above code is self explanatory and highly commented, but still let me give a gist. The setup() and loop() are the 2 main functions of an Arduino sketch. The setup is used to initialise all the hardware and the loop is run repetitively. The only thing we do in the setup is initialize the GSM module so that it can be used for our communications.

The loop function gets the GPS data and updates it to a remote Server only if a GPS position has been detected. When you execute this, you will notice that the blue GPS Led will get lit once we get the position fix.

The requestHTTP() function starts the GPRS and sends a HTTP GET Request to a remote server. In this example I have replaced the IP Address of my target machine with IP.AD.RE.SS. You can replace it with either the IP Address of your target or the domain name. As I was using a machine setup in my home network, I had to use my home IP which I obtained from http://goo.gl/RYtrC

You will notice the GPS Class which is a heavily modified version of the original GPS class provided by Antrax designed to save some memory and bit of extra functionality. The GPS::getGPS() constantly reads the data from the GPS module via SPI interface and monitors it for a GPGGA Sentence which looks like the following:

$GPGGA,092750.000,5321.6802,N,00630.3372,W,1,8,1.03,61.7,M,55.2,M,,*76


This provides us with loads of information regarding the GPS data including the time, Position Altitude and  Number of satellites used, etc. What we care for in our function are just the time and the location data. Note that the above sentence is not for my location.

You will notice that I included the GSM862 library that provides the GSM functions and the SPI library that is a part of the Arduino IDE. The original GSM862 Library can be obtained from here. The code that I am providing is the stripped down version of the library that removes the Telit GPS functions as my module has no use of them and removes a lot of debug messages as they interfered with the GSM communication.

Code for GSM862.h:

/*
 * GM862.h
 * http://tinkerlog.com
 */

#ifndef GM862_h
#define GM862_h

#include "Arduino.h"

#define STATE_NONE 0
#define STATE_ON 1
#define STATE_INITIALIZED 2
#define STATE_REGISTERED 4

class GM862 {

 public:
  GM862(HardwareSerial *modemPort, byte onOffPin, char *pin);

  void init();
  void checkNetwork();

  boolean isOn();
  boolean isInitialized();
  boolean isRegistered();

  void switchOn();
  void switchOff();

  void sendSMS(char *number, char *message);
  void version();

  void initGPRS();
  void enableGPRS();
  void disableGPRS();
  boolean openHTTP(char *domain);
  void send(char *buf);
  char *receive(char *buf);

 private:
  void switchModem();
  byte requestModem(const char *command, uint16_t timeout, boolean check, char *buf);
  byte getsTimeout(char *buf, uint16_t timeout);

  char *readToken(char *str, char *buf, char delimiter);
  char *skip(char *str, char match);

  char pin[5];
  byte state;
  byte onOffPin;
  HardwareSerial *modem;

};

#endif


Code for GSM862.cpp:

/*
 * GM862.cpp
 * http://tinkerlog.com
 */

#include "GM862.h"
#include <string.h>
#define BUF_LENGTH 100

GM862::GM862(HardwareSerial *modemPort, byte onOffPin, char *pin) {
  state = STATE_NONE;
  modem = modemPort;
  modem->begin(9600);  //baud rate for our shield is 9600
  this->onOffPin = onOffPin;
  pinMode(onOffPin, OUTPUT);
  strcpy(this->pin, pin);
}


boolean GM862::isOn() {
  return (state & STATE_ON);
}


boolean GM862::isInitialized() {
  return (state & STATE_INITIALIZED);
}


boolean GM862::isRegistered() {
  return (state & STATE_REGISTERED);
}


void GM862::switchOn() {
  Serial.println("switching on");
  if (!isOn()) {
    switchModem();
    state |= STATE_ON;
  }
  Serial.println("done");
}


void GM862::switchOff() {
  Serial.println("switching off");
  if (isOn()) {
    switchModem();
    state &= ~STATE_ON;
  }
  Serial.println("done");
}


void GM862::switchModem() {
  digitalWrite(onOffPin, HIGH);
  delay(2000);
}


byte GM862::requestModem(const char *command, uint16_t timeout, boolean check, char *buf) {
           
  byte count = 0;

  *buf = 0;

  modem->flush();
  modem->println(command);
  count = getsTimeout(buf, timeout);
  return count;
}


byte GM862::getsTimeout(char *buf, uint16_t timeout) {
  byte count = 0;
  long timeIsOut = 0;
  char c;
  *buf = 0;
  timeIsOut = millis() + timeout;
  while (timeIsOut > millis() && count < (BUF_LENGTH - 1)) { 
    if (modem->available()) {
      count++;
      c = modem->read();
      *buf++ = c;
      timeIsOut = millis() + timeout;
    }
  }
  if (count != 0) {
    *buf = 0;
    count++;
  }
  return count;
}


void GM862::init() {
  char buf[BUF_LENGTH];
  char cmdbuf[30] = "AT+CPIN=";
  strcat(cmdbuf, pin);
  requestModem("AT", 1000, true, buf);
  requestModem("AT+IPR=9600", 1000, true, buf);
  requestModem("AT#SIMDET=1", 1000, true, buf);
  requestModem("AT+CMEE=2", 1000, true, buf);
  requestModem(cmdbuf, 1000, true, buf);
  state |= STATE_INITIALIZED;
}


void GM862::version() {
  char buf[BUF_LENGTH];
  requestModem("AT+GMI", 1000, false, buf);
  requestModem("AT+GMM", 1000, false, buf);
  requestModem("AT+GMR", 1000, false, buf);
  requestModem("AT+CSQ", 1000, false, buf);
}


void GM862::sendSMS(char *number, char *message) {
  char buf[BUF_LENGTH];
  char cmdbuf[30] = "AT+CMGS=\"";
  Serial.println("sending SMS ...");
  requestModem("AT+CMGF=1", 1000, true, buf);             // send text sms
  strcat(cmdbuf, number);
  strcat(cmdbuf, "\"");
  requestModem(cmdbuf, 1000, true, buf);
  modem->print(message);
  modem->write(0x1a);
  getsTimeout(buf, 2000);
  Serial.println(buf);
  Serial.println("done");
}


void GM862::checkNetwork() {
  char buf[BUF_LENGTH];
  char result;
  requestModem("AT+CREG?", 1000, true, buf);
  result = buf[21];

  if (result == '1') {
    state |= STATE_REGISTERED;
  }
  else {
    state &= ~STATE_REGISTERED;
  }
}


/*
 * Vodafone UK Contract
 *   internet, <>, <>
 * TATA DOCOMO India
 *   TATA.DOCOMO.INTERNET, <>, <>
 */
void GM862::initGPRS() {
  char buf[BUF_LENGTH];
  requestModem("AT+CGDCONT=1,\"IP\",\"internet\",\"0.0.0.0\",0,0", 1000, false, buf);
  requestModem("AT#USERID=\"\"", 1000, false, buf);
  requestModem("AT#PASSW=\"\"", 1000, false, buf);
}   


void GM862::enableGPRS() {
  char buf[BUF_LENGTH];
  requestModem("AT#GPRS=1", 1000, false, buf);
  Serial.println("done");
}


void GM862::disableGPRS() {
  char buf[BUF_LENGTH];
  requestModem("AT#GPRS=0", 1000, false, buf);
  Serial.println("done");
}


boolean GM862::openHTTP(char *domain) {
  char buf[BUF_LENGTH];
  char cmdbuf[50] = "AT#SKTD=0,80,\"";
  byte i = 0;
  boolean connect = false;
  strcat(cmdbuf, domain);
  strcat(cmdbuf, "\",0,0\r");
  requestModem(cmdbuf, 1000, false, buf);
  do {
    getsTimeout(buf, 1000);
    if (strstr(buf, "CONNECT")) {;
      connect = true;
      break;
    }
  } while (i++ < 10);
  if (!connect) {
  //  Serial.println("failed");
  }
  return (connect);
}


void GM862::send(char *buf) {
  modem->print(buf);
}


char *GM862::receive(char *buf) {
  getsTimeout(buf, 1000);
  return buf;
}



/*
 * Skips the string until the given char is found.
 */
char *GM862::skip(char *str, char match) {
  uint8_t c = 0;
  while (true) {
    c = *str++;
    if ((c == match) || (c == '\0')) {
      break;
    }
  }
  return str;
}


/*
 * Reads a token from the given string. Token is seperated by the
 * given delimiter.
 */
char *GM862::readToken(char *str, char *buf, char delimiter) {
  uint8_t c = 0;
  while (true) {
    c = *str++;
    if ((c == delimiter) || (c == '\0')) {
      break;
    }
    else if (c != ' ') {
      *buf++ = c;
    }
  }
  *buf = '\0';
  return str;
}


The only thing that you will need to change in the above code is the APN Settings in the GSM862::initGPRS() function. I am using a Vodafone UK Contract Sim and the function is using those settings. I have also provided the APN details for the TATA Docomo Network in India as that is what my final target is.

Now open the GSM_HTTP.ino file in Aduino and you will notice that it has opened all the three files in separate tabs. You can now select File>Upload to compile the Sketch and upload it to the Arduino. If you see an error, it will point out the lines where the errors are. If the upload went successfully, the Arduino execution starts immediately. You should be able to monitor the Serial Console via Tools>Serial Monitor. The GPS Led on the Sheild will glow blue when the GPS position has been determined.


Server Setup
For my Server side setup, I had my Linux machine configured with Apache and PHP. The machine was configured as a DMZ on the Router so that all requests from the outside gets redirected to the local machine. The instructions for this will depend on your Router. The instruction for setting up Apache and PHP can be found elsewhere on the net.

I created a Simple PHP script that would take the inputs and dump them in a file. It also converts the data into coordinates that you can use on Google Maps.

Following is the code for location.php stored in the webserver root.

<?php

function Latitude($lat){ //Converts data to Google Maps acceptable format
  $length=strlen($lat);
   $degree=(integer) substr($lat,0,2);         //Picks up the degrees
  $minutes=(float) substr($lat,2,($length-3)); //Picks up the minutes
  $hemisphere=substr($lat,-1);                 //Picks up the Hemisphere
  $return=$degree + ($minutes/60);             //Converts to Decimal Degree format
  if ( $hemisphere == "S" ) {            // South is negative North is Positive
        $return = $return * -1;
    }
  return $return;
}

function Longitude($long){
//Converts data to Google Maps acceptable format
  $length=strlen($long);
   $degree=(integer) substr($long,0,3);        
//Picks up the degrees
  $minutes=(float) substr($long,3,($length-4)); //Picks up the minutes
  $hemisphere=substr($long,-1);                 //Picks up the Hemisphere
  $return=$degree + ($minutes/60);              //Converts to Decimal Degree format
  if ( $hemisphere == "W" ) {            // West is negative East is Positive
        $return = $return * -1;
    }
  return $return;
}

$time=$_GET[time];
$loc=$_GET[loc];
list($gLatitude,$gLongitude)=explode(",", $location);

$latitude=Latitude($gLatitude);
$longitude=Longitude($gLongitude);

$fh=fopen("filename.txt",'a');
fwrite($fh,"$time : $loc : $latitude,$longitude \n");
echo "done";  //Sends a reply so that the Arduino knows it was a success
fclose($fh);
?>


Now if you tail filename.txt you will notice that a new line is entered every minute with the Time, Coordinates as Obtained from the GPGGA Sentence and Coordinates converted to Google Maps useable format.

You can modify this further to enter the data to a mysql data that can be then used by a HTML file using Google Map API to plot the last known location or location at a given time.

The above example GPGGA sentence would be entered in the file as:
92750 : 5321.6802N,00630.3372W : 53.3613366667,-6.50562

Following link will show this plotted on Google Maps. http://g.co/maps/gcjfc

The GPGGA Sentence was taken from http://en.wikipedia.org/wiki/NMEA_0183 for some location in Ireland.

43 comments:

  1. Nice tutorial! I have an Arduino uno and I tried your code but seems to remain in the do-while loop from getGPS() funtion. Same happends with antrax sample files.
    Have you made something special to get the GPS module to work?
    Thank you

    ReplyDelete
  2. @K: The GPS module takes some time to get the GPS data depending on whether it has connected to enough satellites to get the data.

    For debugging you can try to add a:
    Serial.print(command_result);
    just below:
    gps_data_buffer[6] = command_result;

    inside GPS::getGPS();

    This will print the data sentences that is being received from the GPS module. The one that we care about is the $GPGGA sentence. Make sure you are actually getting a latitude and longitude in the sentence.

    An explanation of this NMEA Sentence is available here: http://aprs.gids.nl/nmea/#gga

    During my testing, I used to keep my kit near the Window to get a fix and still it would take me anywhere betweeen 1 to 5 minutes.

    I am not sure, but the 9V adapter might also be helpful, I know it is required for the GSM module to work properly in low signal conditions.

    ReplyDelete
  3. Thank you very much for your response. I stayed outside the house for half an hour and nothing happened. The producer sent me the new one, rev4, that works.

    ReplyDelete
  4. Nice to know that K.

    Do share your experience with whatever you do with it. :)

    ReplyDelete
  5. Sir/Madam , I am doing Burglar alarm system as my project .....can you please help me how to interface the GSM Module with arduino uno to send a message to mobile whenever there is an interrupt in the burglar alarm.

    my mail id is
    sumanthrevankar2010@gmail.com

    ReplyDelete
  6. @suman:
    If you are sing the GM862 class,
    void GM862::sendSMS(char *number, char *message) is the function you need to use the send the message.

    Assuming you have declared the modem object as in my example, you can call this with the following example:
    modem.sendSMS("07123456789", "Your House is being Robbed");

    ReplyDelete
  7. Hi Sam
    I am setting up a device similar to yours, using the antrax board and an arudino uno. I am following the steps you outlined in your blog, however the device keeps looping at AT+CREG? Have you any suggestions as to why this might be happening or how to fix it ? Monitor output is posted below, Also... is there any way to make sure that the device is getting a gps fix, i waited 20 mins and no blue light on the board..
    Thanks
    Niall

    GSMmonitor
    switching on
    GSM862 monitor
    switching on
    done
    AT
    AT+IPR=9600
    AT#SIMDET=1
    AT+CMEE=2
    AT+CPIN=0000
    AT+GMI
    AT+GMM
    AT+GMR
    AT+CSQ
    AT+CREG?
    AT+CREG?
    AT+CREG?

    ReplyDelete
  8. Hi Niall,

    I have noticed similar behaviour with my steup as well when developing this. The AT+CREG? is used to check if the SIM has registered to the cellular network. I noticed that if the board was connected only to the USB port I would keep seeing this. Once the arduino is connected to the mains supply using a 9v or 12v Adapter it would go away. You can try that.

    Regarding the GPS fix, You can try placing the device near the window.

    ReplyDelete
    Replies
    1. Hi Sam, you were right, it was a power issue, once i connected a 9v battery to the Arduino the AT+CREG? messages went away. I have discovered that the device is getting a gps fix, and i am receiving a GPS signal, however this is nothing is being written to the text file on the server. Is there any way to test that the GPRS connection to the server is being made, that its not refused, and if the locations is actually being transmitted.? for example is there an ACK that i can listen for to say connection established, message sent.. message received ...etc ?

      Niall

      Delete
    2. Also.. do you think a 9v battery is sufficient to power and uno and the gprs/gps shield and send the data to the server ? i am just wondering if again it might be a power issue ?

      Regards
      Niall

      Delete
    3. Hi Niall,

      The 9V is enough to power the Uno and the shield as per my experience.

      As for the issue with no data coming on the server side are you using the original GSM862 files? I had seen a similar issue when I was testing my setup and noticed that this was due to some debug messages from the openHTTP function. Since the Serial communication on the Shield is mapped to the same serial port that we use for debugging the HTTP data being sent to the Shield gets corrupted by the debug messages from the function and it could effect the communication. Try to remove the debug from there.

      For debugging this issue, I was using Wireshark/ethereal on my Server side and watching for packets being sent to my machine's webserver port. If you are using Linux/Apache as your webserver you could even watch out for the access and error logs by tailing them.

      Hope this helps.

      Sorry for the late reply.

      Delete
    4. Hi Sam,
      I'm struggling with the SIM card registration.
      I do recieve the same AT+CREG? messages although I do use the USB and 9V Battery as a power supply.
      I did some debugging as I wanted to see the answer of the function "checkNetwork" in your GM862.cpp file, hoping that this would give me a hint:
      0,0 – SIM Error
      0,2 – Searching
      0,3 – Registration denied
      0,5 – Connected roaming
      0,1 - Connected

      This is the code:

      void GSM862::checkNetwork() {
      char buf[BUF_LENGTH];
      char result;
      requestModem("AT+CREG?", 1000, true, buf);
      result = buf[21];

      Serial.print("Debugging buf2:");
      Serial.print(buf[21]);
      Serial.print("Debugging buf2:");
      Serial.print(buf[1]);
      Serial.print("Debugging buf2:");
      Serial.print(buf[0]);
      Serial.print("Debugging result2:");
      Serial.println(result);

      if (result == '1') {
      state |= STATE_REGISTERED;

      Serial.println("Network registered, home network...");
      }
      else {
      state &= ~STATE_REGISTERED;

      if(result == '0'){
      Serial.println("Network not registered, not searching for a new operator to register to...");
      }
      if(result == '2'){
      Serial.println("Still searching for an operators network to register to...");
      }
      if(result == '3'){
      Serial.println("Network registration denied...");
      }
      if(result == '4'){
      Serial.println("Network registration state unknown, probably still starting up...");
      }
      if(result == '5'){
      Serial.println("Network registered, roaming...");
      }
      }
      }

      So I jumped to the function "requestModem" in GM862.cpp in order to serial.println the "command", "count", "buf" and "timeout" variables.
      This is the code:

      byte GSM862::requestModem(const char *command, uint16_t timeout, boolean check, char *buf) {

      byte count = 0;

      *buf = 0;

      modem->flush();
      modem->println(command);
      count = getsTimeout(buf, timeout);

      Serial.print("Debugging command1:");
      Serial.println(command);
      Serial.print("Debugging count1:");
      Serial.println(count);
      Serial.print("Debugging buf1:");
      Serial.println(buf);
      Serial.print("Debugging timeout1:");
      Serial.println(timeout);

      return count;
      }

      Unfortunately, I do not get a proper value back for "buf", but some cryptic value, which is why the code doesn't recognize it as a 1,2,3,etc as I believe...
      Do you have any ideas what the error could be?

      Thank you and kind regards,
      Daniel

      Delete
    5. Hi Daniel,

      Adding the debug messages breaks the registeration process. This is because the Serial is used for sending the AT commands to the GSM module. The same serial line is also used for printing the debug. When you do this, the debug messages are sent to the GSM module, breaking the command flow.

      You can try adding a simple function that will blink the LED(Pin13) on the Arduino Uno to indicate the status.

      Delete
    6. Hi Sam,
      thank you for your quick answer.
      I get your point (sorry I'm totally new to this).
      But let's say I'd like to display the AT+CREG? answer on the serial monitor depending on the possible values (0,0 – SIM Error, 0,2 – Searching, 0,3 – Registration denied, 0,5 – Connected roaming, 0,1 - Connected), Is that possible at all?And if yes, how?

      Like mentioned before, my SIM900 is stuck at the AT+CREG? loop although its properly set up with power and I somehow need to find out the reason for this.

      Any suggestions?

      Thanks a lot!

      Delete
  9. hi,
    im new to arduino. im just wondering. what is the sim card for?

    ReplyDelete
    Replies
    1. In this project, for sending the GPS data to a remote server via GPRS.

      You could even configure it to send a data as an SMS message to a predefined number.

      Delete
    2. I see, so you would need a data plan then.

      Delete
  10. Hi,

    did not see the mobile # at which the sms to go...did i miss out something in the sketch?

    ReplyDelete
    Replies
    1. This sketch does not send any SMS to any number, hence you won't find it. SMS is costlier than Packet Data.

      Instead it uses GPRS to send HTTP GET Request to a PHP file on a remote server. The IP address for this is marked in the sketch as IP.AD.RE.SS.

      This IP Address should be replaced by either the IP address or the FQDN name of the server in case you are running multiple websites.

      Delete
  11. I mean inclusion of the desired mobile # in the sketch...

    ReplyDelete
  12. Hi Sam!

    Awesome work, congratulations!

    How would it be possible to send the GPS data to a PORT on my Computer, given the PORT number and its IP address?


    Cheers,
    Tiago

    ReplyDelete
    Replies
    1. Hi Tiago,

      It is possible. However, do note that you will need to specify the port in the following line of requestHTTP() function.
      modem.send("HOST: IP.AD.RE.SS port \r\n");

      Hope this helps

      Delete
    2. Hi Sam!

      Thanks for the help!

      I am trying to open a web page through gprs using the following code:

      void requestHTTP() {
      char buf[100];
      byte i = 0;
      modem.initGPRS(); // setup of GPRS context
      modem.enableGPRS(); // switch GPRS on
      modem.openHTTP("www.mypage.com");
      delay(1000);
      while (i++ < 10) { // try to read for 10s
      modem.receive(buf); // read from the socket, timeout 1s
      if (strlen(buf) > 0) { // we received something
      i--; // reset the timeout
      }
      }

      However i am not receiving any answer...
      What am i doing wrong?

      Cheers,
      Tiago

      Delete
    3. Hi Tiago,

      You need to print out the buf somewhere in order to see the received page. I'd recommend it after the while loop.

      Since I had only one Serial that I could effectively use without polluting the input, I had removed it.

      Regards,
      Sam

      Delete
    4. Hi Sam,

      Once again thank you for your answer.
      However I am still unable to use the GPRS to open a web page.

      Here is my code:

      void requestHTTP() {
      char buf[100];
      byte i = 0;
      modem.initGPRS(); // setup of GPRS context
      modem.enableGPRS(); // switch GPRS on
      modem.openHTTP("www.google.com");

      delay(1000);
      while (i++ < 10) { // try to read for 10s
      modem.receive(buf); // read from the socket, timeout 1s


      if (strlen(buf) > 0) { // we received something

      Serial.println(buf);
      i--; // reset the timeout
      }
      }
      modem.disableGPRS(); // switch GPRS off
      }

      And here is the Log:

      AT+CGDCONT=1,"IP","internet.vodafone.pt","0.0.0.0",0,0
      AT#USERID="vodafone"
      AT#PASSW="vodafone"
      AT#GPRS=1
      done
      AT#SKTD=0,80,"www.google.com",0,0
      failed


      I am using an Arduino UNO instead of an Arduino Mega.
      Can it be an issue?
      What am I doing wrong?

      Cheers,
      Tiago

      Delete
  13. Hi Sam. excusame my english, i write from Colombia, and i follow all steps of your how to, but don´t work, the error, show to compile is: !GM862 has not been declared!
    GSM862.cpp:6:19: error: GM862.h: No such file or directory
    GSM862.cpp:9: error: 'GM862' has not been declared

    Please help me, i am new in arduino and don´t understand how to development this error.

    ReplyDelete
    Replies
    1. Hi Bienestartotal,

      You need to include the GM862 Library before you try to compile it.

      Delete
  14. Hi, i want to ask you if the how to work with arduino UNO R3 and the shield SM5100B-D and GPS shield of sparkfun EM 408. I don´t have the form that is working with this shields

    ReplyDelete
    Replies
    1. Hi Bienestartotal,

      You will need to modify the GPS part of this HOWTO to work with your setup. This is because the shield I am using provides the GPS data over the SPI pins. The EM 408 seems to provide via the serial.

      The GSM/GPRS section should work fine with little modifications.

      Delete
  15. Unfortunately it absolutely not working for me.
    I'm getting this error:

    /Applications/Arduino.app/Contents/Resources/Java/libraries/test_gm862/GM862.cpp: In member function 'void GM862::sendSMS(char*, char*)':
    /Applications/Arduino.app/Contents/Resources/Java/libraries/test_gm862/GM862.cpp:159: error: 'BYTE' was not declared in this scope

    I assume it has something to do with the fact that I need to replace Serial.print(byte, BYTE) with Serial.Write(byte) but I don't know how. At GM862.cpp line 159 at the function sendSMS there is only
    modem->print(0x1a, BYTE); and if I change it to modem->print(0x1a); I'm getting hundreds of other errors.

    I'm trying to read our GPS and POST to a web url for months now and also I've bought already 4 GSM modules for now and nothing is working. I was so much hoping that the one from antrax will work with your example.

    I really hope you can help me?

    ReplyDelete
    Replies
    1. Hi basti,

      What is the version of the Arduiono IDE that you are using? Are you using my modified version of the GM862 library or the original version?

      From your comment, I can suggest that you change modem->print(0x1a, BYTE); to modem->Write(0x1a);

      If you are still seeing problems feel free to contact me on g+

      Delete
    2. Thanks. I've got it done finally.
      But only for IP Addresses. If I'm trying to open a domain nothing happens. Do you have an idea?

      Delete
    3. Hi Basti,

      If IP Address works, then the domain name should work too. You can troubleshoot by trying to access the domain name from a phone with the SIM card inserted.

      Some Mobile Networks block some sites due to government regulations on age restrictions. If you are getting an access denied from your phone as well, you can ask the network provider to disable it.

      As a second option. Paste the relevant portion of your code, where you are using the domain name, here and I could help you sort any errors if they exist.

      Regards,
      Sam

      Delete
    4. This comment has been removed by the author.

      Delete
    5. That's the function which I use to open the httpRequest to my server:

      void requestHTTP() {
      Serial.println("requestHTTP");

      char buf[100];
      byte i = 0;
      modem.initGPRS(); // setup of GPRS context
      modem.enableGPRS(); // switch GPRS on

      modem.openHTTP("80.237.132.204"); // Replace IP.AD.RE.SS with your target's IP
      delay(100);
      modem.send("AT&K=0");
      modem.send("GET /light.php"); //Connects to location.php on Server
      modem.send("&loc="); // and
      modem.send(gps.coordinates); //GPS coordinates
      modem.send(" HTTP/1.1\r\n"); //Completes HTTP GET Request
      modem.send("HOST: fahnenstein.de \r\n"); //write on the socket
      modem.send("\r\n"); //Completes the HTTP Connection

      while (i++ < 10) { // try to read for 10s
      modem.receive(buf); // read from the socket, timeout 1s
      if (strlen(buf) > 0) { // we received something
      i--; // reset the timeout
      }
      }
      modem.disableGPRS(); // switch GPRS off
      }

      As you will see I'm already trying to open the http connection with the domains IP and then I do the http Head call with the domain name "fahnenstein.de"
      I can reach the domain via my mobile sim card but somehow it's not reachable from here.

      I also added this AT Command: modem.send("AT&K=0");
      Somebody wrote that this is needed for something - I don't know but at least I was finally able to open my local network via my IP and make a call to my other arduino bord here at my home network.

      Thank you so much for your help!

      Delete
    6. OK, I've startet again from the beginning and copied all your files.
      First of all it seems like there is an error when you are including the files. You are including "#include "GM862.h" instead of "#include "GSM862.h". Right? Or maybe here's my failure already?

      Also after I've set up everything my serial monitor stops at "AT+CREG?"
      And that's all. Maybe you can help me from here to find out the problems with my system?

      Thanks in advance

      Delete
    7. The module is called GM862. It is a modified version of the one from http://tinkerlog.com/2009/05/15/interfacing-arduino-with-a-telit-gm862/

      I had seen the AT+CREG issue when there was weak signal in the house or if there was a stray print statement.

      Delete
  16. i using sim900a i send at commend like

    AT
    AT+CGATT=1
    AT+CGDCONT=1,"IP","airtelgprs.com"
    AT+CSTT="airtelgprs.com"
    AT+CGCLASS="B"
    AT+CIICR
    AT+CIFSR
    AT+CIPSTART="TCP","www.biren.byethost9.com","80"
    AT+CIPSEND
    GET http://www.biren.byethost9.com/VTS/index.php?time=1234 HTTP/1.0
    enter
    HOST: www.biren.byethost9.com
    enter
    enter
    ctrl+z

    i got send ok but data is not update in my log file

    plz help me.

    ReplyDelete
    Replies
    1. Biren, You will need to check the logs on the server side for errors.

      Not sure if it is easy to do with bytehost, but if you can setup a local machine with Apache and portforwarding enabled on the router, you should be able to monitor the error & access logs.

      Delete
  17. Hey Sam,

    Im getting the same problems others had encountered before namely the AT+CREG loop.
    Im using the antrax shield (rev8) in combination with the arduino Uno.

    I already hooked the device on the 9v adapter and tested it outside with clear sky. Sadly it had no effect and the SIM doesnt get GSM network connection.

    When reading youre other blog i came across this sentence " A bit of extra debug code showed out that the library was looking for a character at the wrong index.".

    Is it possible that the newer versions could have te same problem when using youre code intend for the telit GE864?

    If that isnt the problem is it possible that it is caused by the wrong APN Settings?
    I already used the example libary from antrax and the module is working conform that example sketch so the modules are working correctly.

    The APN settings are based on the settings from http://www.ah.nl/mobiel/prepaidbellen/diensten

    And look like this.

    /*
    * Naam AH Internet
    * APN multimedia.ah.nl
    * MMS-Proxy 193.113.200.195
    * MMS-Poort 8080
    */
    void GM862::initGPRS() {
    char buf[BUF_LENGTH];
    requestModem("AT+CGDCONT=1,\"IP\",\"internet\",\"193.113.200.195\",8080,0", 1000, false, buf);
    requestModem("AT#USERID=\"\"", 1000, false, buf);
    requestModem("AT#PASSW=\"\"", 1000, false, buf);
    }

    I hope you can help me because i cant seem to fix the problem.
    Thanks in advance

    Mattijs

    ReplyDelete
    Replies
    1. Hi Mattijs,

      There might be differences in the rev8 and my rev2 board. If you are planning to use the gm862 library and are having issues, I'd recommend you start with testing just the GSM part. Compare it with the example library provided by antrax and make necessary changes.

      When I was testing, I had added some serial prints in the GSM initilisation loop to see if I was getting the expected reply.

      I think your APN is correct.


      Delete
    2. Eey Sam,

      First thanks for youre fast reaction yesterday it gave me a little nudge in the right direction. If been struggling to get the code to work. I ruled out the possibility that i have bad reception, low voltage or a malfunctioning shield. When i use the example library and sketch i can call my cellphone and send GPS coördinations to my phone.

      When i looked closer to the code i noticed that the initialization proces of the GSM is almost the same exept how the are implemented.
      In youre code they are used seperatly and in the example library they are put into serie.

      I tried to put the to libaries to getter and getting a signal lock and initialization. But once i get to the Void requestHTTP part it puts out an endless stream of "ÿÿÿÿÿ".

      When i google on that problem i come to the solution that that means that im reading something with has no input. Have you every had this problem or do you know what couldve done wrong? I haven't changed anything in that part of the code so it should be the same code you provided.

      Thanks in advance

      Matthijs

      Delete
    3. Hi Matthijs,

      It's been a long time since I did it so don't remember if I saw those characters, but I agree it can be a bit of a pain testing that part mainly because the serial of the antrax is the monitor serial. This causes a bit of debugging issues since whatever we print will also be sent to the server.

      First test that the server works independently of the arduino. For example try to pass a dummy value to the PHP from a PC or mobile browser. This will confirm that the server is working.

      Then try to keep as minimal debug prints as you can during the HTTP and see if it works.

      Also on the server script, print something out like OK when the form has accepted. This will let the HTTP command know that the submission worked.

      Regards,
      Sam

      Delete