 
 uint8_t gsmSendCommand(const char* cmd, uint16_t timeout, const char* expected) {
   gsmSerial.listen();
-  
+
   if (cmd) {
     gsmPurgeSerialBuffer();
     gsmSerial.println(cmd);
   }
-  
+
   uint32_t t = millis();
   uint8_t n = 0;
-  
+
   do {
     if (gsmSerial.available()) {
       char c = gsmSerial.read();
       Serial.write(c);
-      
+
       if (n >= sizeof(gsmSerialBuffer) - 1) {
         // buffer full, discard first half
         n = sizeof(gsmSerialBuffer) / 2 - 1;
         memcpy(gsmSerialBuffer, gsmSerialBuffer + sizeof(gsmSerialBuffer) / 2, n);
       }
-      
+
       gsmSerialBuffer[n++] = c;
       gsmSerialBuffer[n] = 0;
-      
+
       if (strstr(gsmSerialBuffer, expected ? expected : "OK\r")) {
-       return n;
+        return n;
       }
     }
   } while (millis() - t < timeout);
+
+  return 0;
+}
+
+uint8_t gsmSendCommand_P(const __FlashStringHelper* cmd, uint16_t timeout, const char* expected) {
+  gsmSerial.listen();
+
+  if (cmd) {
+    gsmPurgeSerialBuffer();
+    gsmSerial.println(cmd);
+  }
+
+  uint32_t t = millis();
+  uint8_t n = 0;
+
+  do {
+    if (gsmSerial.available()) {
+      char c = gsmSerial.read();
+      Serial.write(c);
+
+      if (n >= sizeof(gsmSerialBuffer) - 1) {
+        // buffer full, discard first half
+        n = sizeof(gsmSerialBuffer) / 2 - 1;
+        memcpy(gsmSerialBuffer, gsmSerialBuffer + sizeof(gsmSerialBuffer) / 2, n);
+      }
+
+      gsmSerialBuffer[n++] = c;
+      gsmSerialBuffer[n] = 0;
+
+      if (strstr(gsmSerialBuffer, expected ? expected : "OK\r")) {
+        return n;
+      }
+    }
+  } while (millis() - t < timeout);
+
+  return 0;
+}
+
+void reboot() {
+  digitalWrite(ARDUINO_RESET_PIN, LOW);
+}
+
+void setup() {
+  digitalWrite(ARDUINO_RESET_PIN, HIGH);
+  pinMode(ARDUINO_RESET_PIN, OUTPUT);
   
-  return 0;
-}
-
-void setup() {
   Serial.begin(9600);
   gpsSerial.begin(9600);
   gsmSerial.begin(9600);
 
   for (;;) {
-    Serial.print(F("Initializing GSM... "));
-    while (!gsmInit());
-    Serial.println(F("OK"));
-  
-    Serial.print(F("Setting up network... "));
-    uint8_t ret = gsmSetup(APN);
-    if (ret == 0) break;
+    Serial.println(F("Initializing GSM... "));
+    uint8_t ret = gsmInit();
+    
+    if (ret == 0) {
+      Serial.println(F("OK"));
+      break;
+    }
+    
     Serial.print(F("Error code: "));
     Serial.println(ret);
   }
-  
-  Serial.println(F("OK"));
+
+  for (;;) {
+    Serial.println(F("Setting up network... "));
+    uint8_t ret = gsmSetup(APN);
+    
+    if (ret == 0) {
+      Serial.println(F("OK"));
+      break;
+    }
+    
+    Serial.print(F("Error code: "));
+    Serial.println(ret);
+  }
 }
 
 void loop() {
   gpsSerial.listen();
-  
+
   while (gpsSerial.available()) {
     gps.encode(gpsSerial.read());
     gpsUpdateValues();

  };
}

uint8_t gsmSendGETRequest(const char* url) {
  if (!gsmSendCommand("AT+SAPBR=1,1", 10000)) {
    return 1;
  }
  
  if (!gsmSendCommand("AT+SAPBR=2,1", 10000)) {
    return 2;
  }
  
  if (!gsmSendCommand("AT+HTTPINIT", 5000)) {
    return 3;
  }
  
  if (!gsmSendCommand("AT+HTTPPARA=\"CID\",1", 5000)) {
    return 4;
  }

  gsmSerial.listen();
  gsmSerial.print("AT+HTTPPARA=\"URL\",\"");
  gsmSerial.print(url);
  gsmSerial.println('\"');
  
  if (!gsmSendCommand(0, 5000)) {
    return 5;
  }

  if (!gsmSendCommand("AT+HTTPPARA=\"UA\",\"bekti-tracker\"", 5000)) {
    return 6;
  }

  if (!gsmSendCommand("AT+HTTPPARA=\"TIMEOUT\",30", 5000)) {
    return 7;
  }
  
  if (!gsmSendCommand("AT+HTTPACTION=0", 45000, "+HTTPACTION:")) {
    return 8;
  }
  
  if (!gsmSendCommand("AT+HTTPTERM", 5000)) {
    return 9;
  }

  if (!gsmSendCommand("AT+SAPBR=0,1", 10000)) {
    return 10;
  }
}

uint8_t gsmSendPOSTRequest(const char* url, const char* params) {
  if (!gsmSendCommand("AT+SAPBR=1,1", 10000)) {
    return 1;
  }
  
  if (!gsmSendCommand("AT+SAPBR=2,1", 10000)) {
    return 2;
  }
  
  if (!gsmSendCommand("AT+HTTPINIT", 5000)) {
    return 3;
  }
  
  if (!gsmSendCommand("AT+HTTPPARA=\"CID\",1", 5000)) {
    return 4;
  }

  gsmSerial.listen();
  gsmSerial.print("AT+HTTPPARA=\"URL\",\"");
  gsmSerial.print(url);
  gsmSerial.println('\"');
  
  if (!gsmSendCommand(0, 5000)) {
    return 5;
  }

  if (!gsmSendCommand("AT+HTTPPARA=\"UA\",\"bekti-tracker\"", 5000)) {
    return 6;
  }

  if (!gsmSendCommand("AT+HTTPPARA=\"CONTENT\",\"application/x-www-form-urlencoded\"", 5000)) {
    return 7;
  }

  if (!gsmSendCommand("AT+HTTPPARA=\"TIMEOUT\",30", 5000)) {
    return 8;
  }


uint32_t date, time, speed, course, altitude, satellites, hdop;
uint32_t age, last;
char gsmSerialBuffer[256];
uint8_t failureCount;

void gpsUpdateValues();
uint8_t gsmInit();
uint8_t gsmSetup(const char* apn);
void gsmProcessSMS(uint16_t id, const char* sender, const char* text);
void gsmCheckSMS();
int16_t gsmGetSignalQuality();
void gsmGetBatteryLevel(uint8_t* percentage, uint16_t* voltage);
uint8_t gsmSendGETRequest(const char* url);
uint8_t gsmSendPOSTRequest(const char* url, const char* params);
void gsmPurgeSerialBuffer();
uint8_t gsmSendCommand(const char* cmd, uint16_t timeout = 5000, const char* expected = 0);
uint8_t gsmSendCommand_P(const __FlashStringHelper* cmd, uint16_t timeout = 5000, const char* expected = 0);
void reboot();

const char format_0[] PROGMEM = "id=%d&lat=%c%u.%lu&lng=%c%u.%lu&date=%lu&time=%lu&speed=%lu&course=%lu&alt=%lu&sat=%lu&hdop=%lu&age=%lu&charge=%d&voltage=%u&signal=%d";
const char format_1[] PROGMEM = "id=%d&charge=%d&voltage=%u&signal=%d";

void gpsUpdateValues() {
  if (gps.location.isUpdated()) {
