diff options
-rw-r--r-- | libraries/OBD/OBD.cpp | 129 | ||||
-rw-r--r-- | libraries/OBD/OBD.h | 31 | ||||
-rw-r--r-- | libraries/SIM800/SIM800.cpp | 294 | ||||
-rw-r--r-- | libraries/SIM800/SIM800.h | 55 | ||||
-rw-r--r-- | libraries/SIM800/examples/GPRSTest/GPRSTest.ino | 126 |
5 files changed, 549 insertions, 86 deletions
diff --git a/libraries/OBD/OBD.cpp b/libraries/OBD/OBD.cpp index 42fa1c5..c28c1f2 100644 --- a/libraries/OBD/OBD.cpp +++ b/libraries/OBD/OBD.cpp @@ -6,6 +6,7 @@ *************************************************************************/ #include <Arduino.h> +#include <Wire.h> #include "OBD.h" //#define DEBUG Serial @@ -54,12 +55,12 @@ byte hex2uint8(const char *p) /************************************************************************* * OBD-II UART Adapter *************************************************************************/ -#include <Wire.h> byte COBD::sendCommand(const char* cmd, char* buf) { - write(cmd); - return receive(buf); + write(cmd); + dataIdleLoop(); + return receive(buf); } void COBD::sendQuery(byte pid) @@ -244,12 +245,6 @@ void COBD::sleep() receive(); } -void COBD::wakeup() -{ - write('\r'); - receive(); -} - float COBD::getVoltage() { char buf[OBD_RECV_BUF_SIZE]; @@ -295,46 +290,48 @@ void COBD::begin() { OBDUART.begin(OBD_SERIAL_BAUDRATE); #ifdef DEBUG - DEBUG.begin(115200); + DEBUG.begin(115200); #endif + recover(); } byte COBD::receive(char* buffer, int timeout) { unsigned char n = 0; - for (unsigned long startTime = millis();;) { - if (available()) { - char c = read(); - if (n > 2 && c == '>') { - // prompt char received - break; - } else if (!buffer) { - n++; - } else if (n < OBD_RECV_BUF_SIZE - 1) { - if (c == '.' && n > 2 && buffer[n - 1] == '.' && buffer[n - 2] == '.') { - n = 0; - timeout = OBD_TIMEOUT_LONG; - } else { - buffer[n++] = c; - } - } - } else { - if (millis() - startTime > timeout) { - // timeout - return 0; - } - dataIdleLoop(); - } + unsigned long startTime = millis(); + for (;;) { + if (available()) { + char c = read(); + if (n > 2 && c == '>') { + // prompt char received + break; + } else if (!buffer) { + n++; + } else if (n < OBD_RECV_BUF_SIZE - 1) { + if (c == '.' && n > 2 && buffer[n - 1] == '.' && buffer[n - 2] == '.') { + // waiting siginal + n = 0; + timeout = OBD_TIMEOUT_LONG; + } else { + buffer[n++] = c; + } + } + } else { + if (millis() - startTime > timeout) { + // timeout + break; + } + dataIdleLoop(); + } } - if (buffer) buffer[n] = 0; + if (buffer) buffer[n] = 0; return n; } void COBD::recover() { - write('\r'); - delay(100); - while (available()) read(); + write("AT\r"); + receive(0, 1000); } bool COBD::init(OBD_PROTOCOLS protocol) @@ -403,9 +400,7 @@ bool COBD::setBaudRate(unsigned long baudrate) delay(50); OBDUART.end(); OBDUART.begin(baudrate); - OBDUART.print('ATV\r'); - delay(50); - while (available()) read(); + recover(); return true; } @@ -481,11 +476,10 @@ void COBD::debugOutput(const char *s) void COBDI2C::begin() { Wire.begin(); - memset(obdPid, 0, sizeof(obdPid)); - memset(obdInfo, 0, sizeof(obdInfo)); #ifdef DEBUG - DEBUG.begin(115200); + DEBUG.begin(115200); #endif + recover(); } void COBDI2C::end() @@ -523,35 +517,36 @@ byte COBDI2C::receive(char* buffer, int timeout) { uint32_t start = millis(); byte offset = 0; - delay(10); do { Wire.requestFrom((byte)I2C_ADDR, (byte)MAX_PAYLOAD_SIZE, (byte)1); - - bool hasEnd = false; - for (byte i = 0; i < MAX_PAYLOAD_SIZE && Wire.available(); i++) { - char c = Wire.read(); - buffer[offset + i] = c; - if (c == 0) - hasEnd = true; - } - - if (buffer[0] == 0) { - // data not ready + int c = Wire.read(); + if (offset == 0 && (c == 0 || c == -1)) { + // data not ready dataIdleLoop(); - continue; + continue; } - - offset += MAX_PAYLOAD_SIZE; - if (!hasEnd) { - continue; + if (buffer) buffer[offset++] = c; + for (byte i = 1; i < MAX_PAYLOAD_SIZE && Wire.available(); i++) { + char c = Wire.read(); + if (c == '.' && offset > 2 && buffer[offset - 1] == '.' && buffer[offset - 2] == '.') { + // waiting signal + offset = 0; + timeout = OBD_TIMEOUT_LONG; + } else if (c == 0 || offset == OBD_RECV_BUF_SIZE - 1) { + // string terminator encountered or buffer full + if (buffer) buffer[offset] = 0; + // discard the remaining data + while (Wire.available()) Wire.read(); + return offset; + } else { + if (buffer) buffer[offset++] = c; + } } - - return offset; } while(millis() - start < timeout); return 0; } -void COBDI2C::setPID(byte pid) +void COBDI2C::setPID(byte pid, byte obdPid[]) { byte n = 0; for (; n < MAX_PIDS && obdPid[n]; n++) { @@ -565,16 +560,16 @@ void COBDI2C::setPID(byte pid) obdPid[n] = pid; } -void COBDI2C::applyPIDs() +void COBDI2C::applyPIDs(byte obdPid[]) { - sendCommandBlock(CMD_APPLY_OBD_PIDS, 0, (byte*)obdPid, sizeof(obdPid)); + sendCommandBlock(CMD_APPLY_OBD_PIDS, 0, (byte*)obdPid, sizeof(obdPid[0])* MAX_PIDS); delay(200); } -void COBDI2C::loadData() +void COBDI2C::loadData(PID_INFO obdInfo[]) { sendCommandBlock(CMD_LOAD_OBD_DATA); dataIdleLoop(); Wire.requestFrom((byte)I2C_ADDR, (byte)MAX_PAYLOAD_SIZE, (byte)0); - Wire.readBytes((char*)obdInfo, MAX_PAYLOAD_SIZE); + Wire.readBytes((char*)obdInfo, sizeof(obdInfo[0]) * MAX_PIDS); } diff --git a/libraries/OBD/OBD.h b/libraries/OBD/OBD.h index dcd30fb..74e4225 100644 --- a/libraries/OBD/OBD.h +++ b/libraries/OBD/OBD.h @@ -128,12 +128,10 @@ public: virtual bool read(byte pid, int& result);
// set device into
virtual void sleep();
- // wake up device from previous sleep
- virtual void wakeup();
// set working protocol (default auto)
virtual bool setProtocol(OBD_PROTOCOLS h = PROTO_AUTO);
// send AT command and receive response
- virtual byte sendCommand(const char* cmd, char* buf);
+ virtual byte sendCommand(const char* cmd, char* buf = 0);
// clear diagnostic trouble code
virtual void clearDTC();
// get battery voltage (in 0.1V, e.g. 125 for 12.5V, works without ECU)
@@ -196,8 +194,8 @@ private: #define CMD_SEND_AT_COMMAND 0x11
#define CMD_APPLY_OBD_PIDS 0x12
#define CMD_LOAD_OBD_DATA 0x13
-#define CMD_GPS_SETUP 0x20
-#define CMD_GPS_QUERY 0x22
+#define CMD_GPS_SETUP 0x14
+#define CMD_GPS_QUERY 0x15
typedef struct {
uint16_t age;
@@ -212,22 +210,17 @@ typedef struct { class COBDI2C : public COBD {
public:
- void begin();
+ void begin();
void end();
- bool read(byte pid, int& result);
- void write(const char* s);
+ bool read(byte pid, int& result);
+ void write(const char* s);
// API not applicable
bool setBaudRate(unsigned long baudrate) { return false; }
- // Asynchronized access API
- void setPID(byte pid);
- void applyPIDs();
- void loadData();
- uint16_t getData(byte pid, int& result);
+ // Asynchronized access API
+ void setPID(byte pid, byte obdPid[]);
+ void applyPIDs(byte obdPid[]);
+ void loadData(PID_INFO obdInfo[]);
protected:
- byte receive(char* buffer, int timeout = OBD_TIMEOUT_LONG);
- byte m_addr;
- PID_INFO obdInfo[MAX_PIDS];
- byte obdPid[MAX_PIDS];
-private:
- bool sendCommandBlock(byte cmd, uint8_t data = 0, byte* payload = 0, byte payloadBytes = 0);
+ byte receive(char* buffer = 0, int timeout = OBD_TIMEOUT_SHORT);
+ bool sendCommandBlock(byte cmd, uint8_t data = 0, byte* payload = 0, byte payloadBytes = 0);
};
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(); +} + |