From 4c0720c8dd80bb6d54109a85e779a4008d7e3295 Mon Sep 17 00:00:00 2001
From: Stanley Huang <stanleyhuangyc@gmail.com>
Date: Sun, 24 May 2015 23:43:54 +1000
Subject: Add SIM800 library

---
 libraries/SIM800/SIM800.cpp                     | 294 ++++++++++++++++++++++++
 libraries/SIM800/SIM800.h                       |  55 +++++
 libraries/SIM800/examples/GPRSTest/GPRSTest.ino | 126 ++++++++++
 3 files changed, 475 insertions(+)
 create mode 100644 libraries/SIM800/SIM800.cpp
 create mode 100644 libraries/SIM800/SIM800.h
 create mode 100644 libraries/SIM800/examples/GPRSTest/GPRSTest.ino

diff --git a/libraries/SIM800/SIM800.cpp b/libraries/SIM800/SIM800.cpp
new file mode 100644
index 0000000..7a63482
--- /dev/null
+++ b/libraries/SIM800/SIM800.cpp
@@ -0,0 +1,294 @@
+/*************************************************************************
+* Test sketch for SIM800 library
+* Distributed under GPL v2.0
+* Written by Stanley Huang <stanleyhuangyc@gmail.com>
+* For more information, please visit http://arduinodev.com
+*************************************************************************/
+
+#include "SIM800.h"
+
+bool CGPRS_SIM800::init()
+{
+    simser.begin(115200);
+    pinMode(SIM800_RESET_PIN, OUTPUT);
+    digitalWrite(SIM800_RESET_PIN, HIGH);
+    delay(10);
+    digitalWrite(SIM800_RESET_PIN, LOW);
+    delay(100);
+    // generate turn on pulse
+    digitalWrite(SIM800_RESET_PIN, HIGH);
+    delay(3000);
+    if (sendCommand("AT")) {
+        sendCommand("AT+IPR=115200");
+        sendCommand("ATE0");
+        return true;
+    }
+    return false;
+}
+byte CGPRS_SIM800::setup(const char* apn)
+{
+  bool success = false;
+  for (byte n = 0; n < 30; n++) {
+    if (sendCommand("AT+CREG?", 2000)) {
+        char *p = strstr(buffer, "0,");
+        if (p) {
+          char mode = *(p + 2);
+#if DEBUG
+          con.print("Mode:");
+          con.println(mode);
+#endif
+          if (mode == '1' || mode == '5') {
+            success = true;
+            break;
+          }
+        }
+    }
+    delay(1000);
+  }
+  		
+  if (!success)
+    return 1;
+  
+  if (!sendCommand("AT+CGATT?"))
+    return 2;
+    
+  if (!sendCommand("AT+SAPBR=3,1,\"Contype\",\"GPRS\""))
+    return 3;
+  
+  simser.print("AT+SAPBR=3,1,\"APN\",\"");
+  simser.print(apn);
+  simser.println('\"');
+  if (!sendCommand(0))
+    return 4;
+  
+  for (byte n = 0; n < 10 && !(success = (sendCommand("AT+SAPBR=1,1") != 0)); n++)
+    delay(500);
+  
+  if (!success)
+    return 5;
+
+  return 0;
+}
+bool CGPRS_SIM800::getOperatorName()
+{
+  // display operator name
+  if (sendCommand("AT+COPS?", "OK\r", "ERROR\r") == 1) {
+      char *p = strstr(buffer, ",\"");
+      if (p) {
+          p += 2;
+          char *s = strchr(p, '\"');
+          if (s) *s = 0;
+          strcpy(buffer, p);
+          return true;
+      }
+  }
+  return false;
+}
+bool CGPRS_SIM800::checkSMS()
+{
+  if (sendCommand("AT+CMGR=1", "+CMGR:", "ERROR") == 1) {
+    // reads the data of the SMS
+    sendCommand(0, 100, "\r\n");
+    if (sendCommand(0)) {
+      // remove the SMS
+      sendCommand("AT+CMGD=1");
+      return true;
+    }
+  }
+  return false; 
+}
+int CGPRS_SIM800::getSignalQuality()
+{
+  sendCommand("AT+CSQ");
+  char *p = strstr(buffer, "CSQ: ");
+  if (p) {
+    int n = atoi(p + 2);
+    if (n == 99 || n == -1) return 0;
+    return n * 2 - 114;
+  } else {
+   return 0; 
+  }
+}
+void CGPRS_SIM800::httpUninit()
+{
+  sendCommand("AT+HTTPTERM");
+}
+
+bool CGPRS_SIM800::httpInit()
+{
+  if  (!sendCommand("AT+HTTPINIT", 10000) || !sendCommand("AT+HTTPPARA=\"CID\",1", 5000)) {
+    httpState = HTTP_DISABLED;
+    return false;
+  }
+  httpState = HTTP_READY;
+  return true;
+}
+bool CGPRS_SIM800::httpConnect(const char* url, const char* args)
+{
+    // Sets url
+    simser.print("AT+HTTPPARA=\"URL\",\"");
+    simser.print(url);
+    if (args) {
+        simser.print('?');
+        simser.print(args);
+    }
+
+    simser.println('\"');
+    if (sendCommand(0))
+    {
+        // Starts GET action
+        simser.println("AT+HTTPACTION=0");
+        httpState = HTTP_CONNECTING;
+        bytesRecv = 0;
+        checkTimer = millis();
+    } else {
+        httpState = HTTP_ERROR;
+    }
+    return false;
+}
+// check if HTTP connection is established
+// return 0 for in progress, 1 for success, 2 for error
+byte CGPRS_SIM800::httpIsConnected()
+{
+    byte ret = checkbuffer("0,200", "0,60", 10000);
+    if (ret >= 2) {
+        httpState = HTTP_ERROR;
+        return -1;
+    }
+    return ret;
+}
+void CGPRS_SIM800::httpRead()
+{
+    simser.println("AT+HTTPREAD");
+    httpState = HTTP_READING;
+    bytesRecv = 0;
+    checkTimer = millis();
+}
+// check if HTTP connection is established
+// return 0 for in progress, -1 for error, number of http payload bytes on success
+int CGPRS_SIM800::httpIsRead()
+{
+    byte ret = checkbuffer("+HTTPREAD: ", "Error", 10000) == 1;
+    if (ret == 1) {
+        bytesRecv = 0;
+        // read the rest data
+        sendCommand(0, 100, "\r\n");
+        int bytes = atoi(buffer);
+        sendCommand(0);
+        bytes = min(bytes, sizeof(buffer) - 1);
+        buffer[bytes] = 0;
+        return bytes;
+    } else if (ret >= 2) {
+        httpState = HTTP_ERROR;
+        return -1;
+    }
+    return 0;
+}
+byte CGPRS_SIM800::sendCommand(const char* cmd, unsigned int timeout, const char* expected)
+{
+  if (cmd) {
+    purgeSerial();
+#if DEBUG
+    con.print('>');
+    con.println(cmd);
+#endif
+    simser.println(cmd);
+  }
+  uint32_t t = millis();
+  byte n = 0;
+  do {
+    if (simser.available()) {
+      char c = simser.read();
+      if (n >= sizeof(buffer) - 1) {
+        // buffer full, discard first half
+        n = sizeof(buffer) / 2 - 1;
+        memcpy(buffer, buffer + sizeof(buffer) / 2, n);
+      }
+      buffer[n++] = c;
+      buffer[n] = 0;
+      if (strstr(buffer, expected ? expected : "OK\r")) {
+#if DEBUG
+       con.print("[1]");
+       con.println(buffer);
+#endif
+       return n;
+      }
+    }
+  } while (millis() - t < timeout);
+#if DEBUG
+   con.print("[0]");
+   con.println(buffer);
+#endif
+  return 0;
+}
+byte CGPRS_SIM800::sendCommand(const char* cmd, const char* expected1, const char* expected2, unsigned int timeout)
+{
+  if (cmd) {
+    purgeSerial();
+#if DEBUG
+    con.print('>');
+    con.println(cmd);
+#endif
+    simser.println(cmd);
+  }
+  uint32_t t = millis();
+  byte n = 0;
+  do {
+    if (simser.available()) {
+      char c = simser.read();
+      if (n >= sizeof(buffer) - 1) {
+        // buffer full, discard first half
+        n = sizeof(buffer) / 2 - 1;
+        memcpy(buffer, buffer + sizeof(buffer) / 2, n);
+      }
+      buffer[n++] = c;
+      buffer[n] = 0;
+      if (strstr(buffer, expected1)) {
+#if DEBUG
+       con.print("[1]");
+       con.println(buffer);
+#endif
+       return 1;
+      }
+      if (strstr(buffer, expected2)) {
+#if DEBUG
+       con.print("[2]");
+       con.println(buffer);
+#endif
+       return 2;
+      }
+    }
+  } while (millis() - t < timeout);
+#if DEBUG
+   con.print("[0]");
+   con.println(buffer);
+#endif
+  return 0;
+}
+
+byte CGPRS_SIM800::checkbuffer(const char* expected1, const char* expected2, unsigned int timeout)
+{
+    while (simser.available()) {
+        char c = simser.read();
+        if (bytesRecv >= sizeof(buffer) - 1) {
+            // buffer full, discard first half
+            bytesRecv = sizeof(buffer) / 2 - 1;
+            memcpy(buffer, buffer + sizeof(buffer) / 2, bytesRecv);
+        }
+        buffer[bytesRecv++] = c;
+        buffer[bytesRecv] = 0;
+        if (strstr(buffer, expected1)) {
+            return 1;
+        }
+        if (expected2 && strstr(buffer, expected2)) {
+            return 2;
+        }
+    }
+    return (millis() - checkTimer < timeout) ? 0 : 3;
+}
+
+void CGPRS_SIM800::purgeSerial()
+{
+  while (simser.available()) simser.read();
+}
+
diff --git a/libraries/SIM800/SIM800.h b/libraries/SIM800/SIM800.h
new file mode 100644
index 0000000..ca3104f
--- /dev/null
+++ b/libraries/SIM800/SIM800.h
@@ -0,0 +1,55 @@
+/*************************************************************************
+* Test sketch for SIM800 library
+* Distributed under GPL v2.0
+* Written by Stanley Huang <stanleyhuangyc@gmail.com>
+* For more information, please visit http://arduinodev.com
+*************************************************************************/
+
+#include <Arduino.h>
+
+#define SIM800_RESET_PIN 7
+#define simser Serial1
+#define con Serial
+#define DEBUG 0
+
+typedef enum {
+    HTTP_DISABLED = 0,
+    HTTP_READY,
+    HTTP_CONNECTING,
+    HTTP_READING,
+    HTTP_ERROR,
+} HTTP_STATES;
+
+class CGPRS_SIM800 {
+public:
+    CGPRS_SIM800():httpState(HTTP_DISABLED) {}
+    bool init();
+    byte setup(const char* apn);
+    bool getOperatorName();
+    bool checkSMS();
+    int getSignalQuality();
+    void httpUninit();
+    bool httpInit();
+    bool httpConnect(const char* url, const char* args = 0);
+    // check if HTTP connection is established
+    // return 0 for in progress, 1 for success, 2 for error
+    byte httpIsConnected();
+    void httpRead();
+    // check if HTTP connection is established
+    // return 0 for in progress, -1 for error, number of http payload bytes on success
+    int httpIsRead();
+    byte sendCommand(const char* cmd, unsigned int timeout = 2000, const char* expected = 0);
+    byte sendCommand(const char* cmd, const char* expected1, const char* expected2, unsigned int timeout = 2000);
+    bool available()
+    {
+      return simser.available(); 
+    }
+    char buffer[256];
+    byte httpState;
+private:
+    byte checkbuffer(const char* expected1, const char* expected2 = 0, unsigned int timeout = 2000);
+    void purgeSerial();
+    byte bytesRecv;
+    uint32_t checkTimer;
+};
+
diff --git a/libraries/SIM800/examples/GPRSTest/GPRSTest.ino b/libraries/SIM800/examples/GPRSTest/GPRSTest.ino
new file mode 100644
index 0000000..e752166
--- /dev/null
+++ b/libraries/SIM800/examples/GPRSTest/GPRSTest.ino
@@ -0,0 +1,126 @@
+/*************************************************************************
+* Test sketch for SIM800 library
+* Distributed under GPL v2.0
+* Written by Stanley Huang <stanleyhuangyc@gmail.com>
+* For more information, please visit http://arduinodev.com
+*************************************************************************/
+
+#include "SIM800.h"
+
+#define APN "connect"
+static const char* url = "http://arduinodev.com/datetime.php";
+
+
+CGPRS_SIM800 gprs;
+uint32_t count = 0;
+uint32_t errors = 0;
+
+void setup()
+{
+  con.begin(9600);
+  while (!con);
+
+  con.println("SIM800 TEST");
+
+  for (;;) {
+    con.print("Resetting...");
+    while (!gprs.init()) {
+      con.write('.');
+    }
+    con.println("OK");
+    
+    con.print("Setting up network...");
+    byte ret = gprs.setup(APN);
+    if (ret == 0)
+      break;
+    con.print("Error code:");
+    con.println(ret);
+    con.println(gprs.buffer);
+  }
+  con.println("OK");
+  delay(3000);  
+  
+  if (gprs.getOperatorName()) {
+    con.print("Operator:");
+    con.println(gprs.buffer);
+  }
+  int ret = gprs.getSignalQuality();
+  if (ret) {
+     con.print("Signal:");
+     con.print(ret);
+     con.println("dB");
+  }
+ 
+#if 0
+  sendCommand("AT+CSQ");
+  lcd.println("Dialing...");
+  if (sendCommand("ATD + +61402533012;", 10000)) {
+    lcd.println(buffer); 
+  }
+  if (sendCommand("ATH"))
+    lcd.println(buffer);
+  delay(1000);
+#endif
+
+  gprs.sendCommand("AT+CMGF=1");    // sets the SMS mode to text
+  gprs.sendCommand("AT+CPMS=\"SM\",\"SM\",\"SM\""); // selects the memory
+
+  for (;;) {
+    if (gprs.httpInit()) break;
+    con.println(gprs.buffer);
+    gprs.httpUninit();
+    delay(1000);
+  }
+  delay(3000);
+}
+
+void loop()
+{
+  count++;
+  
+  char mydata[16];
+  sprintf(mydata, "t=%lu", millis());
+  con.print("Requesting ");
+  con.print(url);
+  con.print('?');
+  con.println(mydata);
+  gprs.httpConnect(url, mydata);
+  while (gprs.httpIsConnected() == 0) {
+    // can do something here while waiting
+    con.write('.');
+    for (byte n = 0; n < 25 && !gprs.available(); n++) {
+      delay(10);
+    }
+  }
+  if (gprs.httpState == HTTP_ERROR) {
+    con.println("error");
+    errors++;
+    delay(3000);
+    return; 
+  }
+  gprs.httpRead();
+  int ret;
+  while ((ret = gprs.httpIsRead()) == 0) {
+    // can do something here while waiting
+  }
+  if (gprs.httpState == HTTP_ERROR) {
+    con.println("error");
+    errors++;
+    delay(3000);
+    return; 
+  }
+
+  // now we have received payload
+  con.print("\n[Payload]");
+  con.println(gprs.buffer);
+  
+  // show stats  
+  con.print("Total Requests:");
+  con.print(count);
+  if (errors) {
+    con.print(" Errors:");
+    con.print(errors);
+  }
+  con.println();
+}
+
-- 
cgit v1.2.3