3G Shield library, port for mbed. (from http://3gsa.org/ ) see: https://developer.mbed.org/users/phsfan/notebook/phsshield/
Dependents: PHSShield_test PHSShield_connectTCP PHSShield_Twitter PHSShield_httpGET
Diff: a3gs.cpp
- Revision:
- 0:ca471c239d5f
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/a3gs.cpp Tue Mar 10 01:12:17 2015 +0000 @@ -0,0 +1,1898 @@ +//*********************************************************** +// a3gs.cpp -- IEM 3G Sheild for Arduino Control Library +// +// History: +// R1.0 2012/10/06 1st Release for IEM 3G Shiled(Ver1.0) +// R1.1 2012/10/14 2nd Release(Operate by few memories) +// (modify sendSMS(),onSMSReceived(),httpGET(),httpPOST(),tweet(),connectTCP()) +// R1.2 2012/10/28 Bug fix (httpGET(), httpPOST(), tweet(), availableSMS() and redSMS()) +// R1.3 2013/01/01 Support "https" in httpGET() and httpPost() [if gw3g version is above 1.1] +// R1.4 2013/04/16 Bug fix (discardUntil() has never return) +// R2.0 2013/07/12 Change interface of TCP/IP and discardUntil() +// some bugs fix(httpPOST, httpGET, read and getResult) +// R2.1 2013/08/17 Buf fix (discardUntil() has never return) +// R2.2 2013/10/27 Bug fix (read(res, reslength)) +// R2.3 2014/07/06 Support binary data in read() and add new version read() function, bug fix write() +// R3.0 2014/08/30 Support for gw3g R2.0 and add follow functions: +// setAirplaneMode(), put(), get() +// +// Author: +// 3G Shield Alliance and Atushi Daikoku +// +// Notes: +// Lower compatible with Arduino GSM/GPRS Shield library. +// Notices as bellow: +// - Use SoftwareSerial library (RxD is D4, TxD is D5). +// - Use Interrupt 0(D2) for SMS arrival notification. +// - Use D6 and D7 are used for Power control. +// If You use Leonard, Mega or ADK(Mega2560) then you must change IEM_RXD_PIN and IEM_TXD_PIN for suitable. +//*********************************************************** +/* Modified by 2015 phsfan + * for ABIT PHS Shield on mbed + */ + +//#define DEBUG 1 // Define if you want to debug + +#include "mbed.h" +#include "a3gs.h" + +// Macros +#ifdef DEBUG +# define DEBUG_PRINT(m,v) { printf("%s:%s\r\n", m, v); } +# define DEBUG_PRINT_NUM(m,v) { printf("%s:%d\r\n", m, v); } +# define DBG(...) printf("" __VA_ARGS__); +#else +# define DEBUG_PRINT(m,v) // do nothing +# define DEBUG_PRINT_NUM(m,v) // do nothing +# define DBG(...) +#endif + // Constants for pins +#define IEM_INT_PIN 2 // D2(INT0) +#define IEM_RXD_PIN 4 // D4(For example,If you use Leonardo or Mega etc. then change to D10..) +#define IEM_TXD_PIN 5 // D5(For example,If you use Leonardo or Mega etc. then change to D11..) +#define IEM_POWER_PIN 6 // D6 +#define IEM_REGULATOR_PIN 7 // D7 + // Constants for getTime2() +#define SECS_PER_MIN (60UL) +#define SECS_PER_HOUR (3600UL) +#define SECS_PER_DAY (SECS_PER_HOUR * 24UL) +#define DAYS_PER_WEEK (7UL) +#define SECS_YR_2000 (946684800UL) // the time at the start of y2k + // Leap year calulator expects year argument as years offset from 1970 +#define LEAP_YEAR(Y) (((1970+Y)>0) && !((1970+Y)%4) && (((1970+Y)%100) || !((1970+Y)%400))) + // Command execution timeout values +#define TIMEOUT_LOCAL 5000 // Timeout value of local functions [mS] +#define TIMEOUT_NETWORK 35000 // Timeout value of communication functions [mS] +#define TIMEOUT_GPS 180000 // Timeout value og GPS locationing [mS] + // Misc. +#define ISDIGIT(c) ((c) >= '0' && (c) <= '9') + // Interrupt number for SMS +#define INTNO_SMS 0 // Use INT0 + // IEM Version +#define MIN_IEM_VERSION 2.0 // A necessary minimum IEM version of this library + +// Global variables +static char gWorkBuffer[256]; // Buffer for working(Mega..) +static void (*SMShandler)(void); // ISR for SMS Notification + + +A3GS::A3GS(PinName tx, PinName rx, PinName intin, PinName power, PinName reg, int baud) : + iemSerial(tx, rx), _intin(intin), _power(power), _reg(reg) +{ + iemSerial.baud(baud); + _intin.mode(PullDown); + _power = 0; + _reg = 0; +} + +//*************************** +// begin() +// +// @description +// Begin to use 3G shield function +// @return value +// 0 .. OK(at least, Packet Switch or Circuit Switch is availabled) +// otherwise .. NG +// @param +// pin : Not used +// @note +// +//*************************** +int A3GS::begin(char* pin) +{ + char version[a3gsMAX_VERSION_LENGTH+1]; +//-- + DEBUG_PRINT(">begin()", "default"); + + // Initilalize global variables and detach INT0 + _status = IDLE; + SMShandler = NULL; + _intin.fall(NULL); + + // Get iem version and check it + if (getVersion(version) != 0) + return 1; // NG -- Can't get version + + if (atof(version) < MIN_IEM_VERSION) { + DEBUG_PRINT(">getVersion()", "IEM version is old"); + return 2; // NG -- IEM Version is old + } + + return a3gsSUCCESS; // OK +} + +//*************************** +// begin() +// +// @description +// Begin to use 3G shield function +// @return value +// 0 .. OK(at least, Packet Switch or Circuit Switch is availabled) +// otherwise .. NG +// @param +// pin : Not used +// baudrate : baudrate to begin (2400/4800/9600/19200/38400/57600/115200) +// @note +// This function use to specify non-default baudrate. +//*************************** +int A3GS::begin(char* pin, uint32_t baudrate) +{ + char version[a3gsMAX_VERSION_LENGTH+1]; +//-- + DEBUG_PRINT_NUM(">begin()", baudrate); + + iemSerial.baud(baudrate); + + // Initilalize global variables and detach INT0 + _status = IDLE; + SMShandler = NULL; + _intin.fall(NULL); + + // Get iem version and check it + if (getVersion(version) != 0) + return 1; // NG -- Can't get version + + if (atof(version) < MIN_IEM_VERSION) { + DEBUG_PRINT(">getVersion()", "IEM version is old"); + return 2; // NG -- IEM Version is old + } + + return a3gsSUCCESS; // OK +} + +//*************************** +// end() +// +// @description +// End to use 3G shield function +// @return value +// 0 .. always +// @param +// none +// @note +// re-enable serial communication, call a3gs.begin() +//*************************** +int A3GS::end(void) +{ + // Clear interrupt handler + if (SMShandler != NULL) { + _intin.fall(NULL); + SMShandler = NULL; + } + + return a3gsSUCCESS; // OK +} + +//*************************** +// restart() +// +// @description +// Restart 3G shield and clear SMS handler +// @return value +// 0 .. always +// @param +// pin : Not used +// @note +// Reboot time is about 40 Sec. +//*************************** +int A3GS::restart(char* pin) +{ + // Clear interrupt handler + if (SMShandler != NULL) { + _intin.fall(NULL); + SMShandler = NULL; + } + + sendCommand("$YE"); // Send "Reset IEM" Command + + return a3gsSUCCESS; // OK +} + +//*************************** +// start() +// +// @description +// Power on 3G shield and wait for ready to use +// @return value +// 0 .. always +// @param +// pin : Not used +// @note +// Start up time is about 40 Sec. +//*************************** +int A3GS::start(char* pin) +{ + _reg = 1; // Regulator turn on + wait_ms(1000); // Wait a moment + _power = 0; + wait_ms(2000); // Make low STATUS_PB_WALK -> Turn on IEM + _power = 1; + + DEBUG_PRINT(">start()", "Turn on and wait for a moment.."); + + wait_ms(35000); // Wait for ready IEM +// wait_ms(1000); // Wait for ready IEM + + DEBUG_PRINT(">start()", "IEM is available now."); + + return a3gsSUCCESS; // OK +} + +//*************************** +// shutdown() +// +// @description +// Power off 3G shield +// @return value +// 0 .. always +// @param +// none +// @note +// Shutdown time is about 15 Sec. +//*************************** +int A3GS::shutdown(void) +{ + sendCommand("$YE"); // Send "Reset IEM" Command + + wait_ms(15000); // Wait a moment + + _reg = 0; // Regulator turn off + + return a3gsSUCCESS; // OK +} + +//*************************** +// getService +// +// @description +// Get network service status +// @return value +// 0 .. Succeeded, otherwise .. Failed +// @param +// status .. [OUT] SRV* (see a3gs.h) +// @note +// +//*************************** +int A3GS::getServices(int& status) +{ + char responses[12]; // Format "$YS=OK 9" or "$YS=NG errno" + int length = sizeof(responses); +//-- + sendCommand("$YS"); // Send "Get Services" command + + if (getResult(responses, &length, TIMEOUT_LOCAL)) + return 1; // NG -- maybe timeout + + DEBUG_PRINT(">getServices()", responses); + + // parse response + switch (responses[7]) { + case '0' : // NO_SRV + status = a3gsSRV_NO; + break; + case '1' : // PS_ONLY + status = a3gsSRV_PS; + break; + case '2' : // CS_ONLY + status = a3gsSRV_CS; + break; + case '3' : // BOTH + status = a3gsSRV_BOTH; + break; + default : // bug + return 1; // NG -- Can't get service + } + + return a3gsSUCCESS; // OK +} + +//*************************** +// getIMEI() +// +// @description +// Get IEM's IMEI +// @return value +// 0 .. Succeeded +// otherwise .. Failed +// @param +// imei : [OUT] IMEI (a3gsIMEI_SIZE bytes space requred) +// @note +// +//*************************** +int A3GS::getIMEI(char* imei) +{ + char responses[a3gsIMEI_SIZE+10]; // Format "$YI=OK 99..99" or "$YI=NG errno" + int length = sizeof(responses); +//-- + sendCommand("$YI"); // Send "Get IMEI" command + + if (getResult(responses, &length, TIMEOUT_LOCAL)) + return 1; // NG -- maybe timeout + + DEBUG_PRINT(">getIMEI()", responses); + + // parse response + if (strncmp(responses, "$YI=OK", 6)) + return 1; // NG -- Can't get IMEI + + strncpy(imei, responses+7, a3gsIMEI_SIZE); + imei[a3gsIMEI_SIZE] = '\0'; + + return a3gsSUCCESS; // OK +} + +//*************************** +// setBaudrate +// +// @description +// Set UART baudrate +// @return value +// 0 .. OK +// 1 .. NG +// @param +// baudrate : baudrate to set (2400/4800/9600/19200/38400/57600/115200) +// @note +// New baudrate will be validated after reset IEM +//*************************** +int A3GS::setBaudrate(uint32_t baudrate) +{ + char command[13]; + char responses[12]; // Format "$YB=OK" or "$YB=NG errno" + int length = sizeof(responses); +//-- + switch (baudrate) { + case 2400 : + case 4800 : + case 9600 : + case 19200 : + case 38400 : + case 57600 : + case 115200 : + break; + default : + return 1; // NG -- Bad parameter + } + + // Make command and send it + sprintf(command, "$YB %lu", baudrate); + sendCommand(command); // Send "Set Baudrate" command + + if (getResult(responses, &length, TIMEOUT_LOCAL)) + return 1; // NG -- maybe timeout + + DEBUG_PRINT(">setBaudrate()", responses); + + // parse response + if (strncmp(responses, "$YB=OK", 6)) + return 1; // NG -- Can't set baudrate + + return a3gsSUCCESS; // OK +} + +//*************************** +// setLED +// +// @description +// Set LED On/Off +// @return value +// 0 .. OK +// 1 .. NG +// @param +// sw : true is On, false is Off +// @note +// There is LED on 3G shield board(named LED1) +//*************************** +int A3GS::setLED(bool sw) +{ + char command[10]; + char responses[12]; // Format "$YL=OK" or "$YL=NG errno" + int length = sizeof(responses); +//-- + // Make command and send it + sprintf(command, "$YL %d", (sw ? 1 : 0)); + sendCommand(command); // Send "Set LED" command + + if (getResult(responses, &length, TIMEOUT_LOCAL)) + return 1; // NG -- maybe timeout + + DEBUG_PRINT(">setLED()", responses); + + // parse response + if (strncmp(responses, "$YL=OK", 6)) + return 1; // NG -- Can't set led + + return a3gsSUCCESS; // OK +} + +//*************************** +// setAirplaneMode +// +// @description +// Set airplane mode +// @return value +// 0 .. OK +// 1 .. NG +// @param +// sw : true is On(Airplane mode), false is Off(Normal mode) +// @note +// R3.0 add +//*************************** +int A3GS::setAirplaneMode(bool sw) +{ + char command[10]; + char responses[12]; // Format "$YP=OK" or "$YP=NG errno" + int length = sizeof(responses); +//-- + // Make command and send it + sprintf(command, "$YP %d", (sw ? 1 : 0)); + sendCommand(command); // Send "Set Airplane mode" command + + if (getResult(responses, &length, TIMEOUT_LOCAL)) + return 1; // NG -- maybe timeout + + DEBUG_PRINT(">setAirplaneMode()", responses); + + // parse response + if (strncmp(responses, "$YP=OK", 6)) + return 1; // NG -- Can't set airplane mode + + return a3gsSUCCESS; // OK +} + +//*************************** +// sendSMS +// +// @description +// send SMS +// @return value +// 0 .. OK +// otherwise .. NG +// @param +// to : MSN(10 digits) +// msg : message string(ASCII or UNICODE) +// encode : message's char set(default is ASCII) +//*************************** +int A3GS::sendSMS(const char* to, const char* msg, int encode) +{ + char responses[20]; // FORMAT: "$SS=OK" or "$SS=NG errno" + int length = sizeof(responses); +//-- + // Check parameter sizes + if (strlen(msg) > a3gsMAX_SMS_LENGTH) + return 1; // NG - too long message + if (strlen(to) > a3gsMAX_MSN_LENGTH) + return 1; // NG - too long msn + + // Send comamnd little by little + sendData("$SS "); + sendData(to); + sendData(" \""); + sendData(msg); + sendData("\" "); + if (encode == a3gsCS_UNICODE) + sendCommand("UNICODE"); + else + sendCommand("ASCII"); + + DEBUG_PRINT(">sendSMS", to); + + if (getResult(responses, &length, TIMEOUT_NETWORK)) + return 1; // NG -- maybe timeout + + DEBUG_PRINT(">sendSMS()", responses); + + if (strncmp(responses, "$SS=OK", 6)) + return 1; // NG -- send error + + return a3gsSUCCESS; // OK +} + +//*************************** +// availableSMS +// +// @description +// Check SMS is available or not +// @return value +// true .. Available +// false .. Not Available +// @param +// none +// @note +// +//*************************** +bool A3GS::availableSMS() +{ + char responses[20]; // FORMAT: "$SC=OK n" or "$SC=NG errno" + int length = sizeof(responses); +//-- + sendCommand("$SC"); // Send "Check SMS" command + + if (getResult(responses, &length, TIMEOUT_LOCAL)) + return false; // NG -- maybe timeout + + DEBUG_PRINT(">availableSMS()", responses); + + if (strncmp(responses, "$SC=OK 1", 8)) + return false; // Not available + + return true; // Available +} + +//*************************** +// readSMS +// +// @description +// Read received SMS +// @return value +// 0 .. OK +// otherwise .. NG +// @param +// msg : [OUT] read message string +// msglength : msg length(max a3gsMAX_SMS_LENGTH) +// number : [OUT] MSN +// nlength : MSN length(max a3gsMAX_MSN_LENGTH) +// @note +// Use gWorkBuffer and destory it +//*************************** +int A3GS::readSMS(char* msg, int msglength, char* number, int nlength) +{ + int length = sizeof(gWorkBuffer); + char *cp; +//-- + sendCommand("$SR"); // Send "Read SMS" command + + if (getResult(gWorkBuffer, &length, TIMEOUT_LOCAL)) + return 1; // NG -- maybe timeout + + if (! strncmp(gWorkBuffer, "$SR=NG", 6)) + return 1; // NG -- No SMS + + // Parse number(msn) + for (cp = gWorkBuffer+7; *cp != '\0'; cp++) { + while (ISDIGIT(*cp) && nlength-- > 1) + *number++ = *cp++; + *number = '\0'; + DEBUG_PRINT(">readSMS() msn", number); + break; + } + + // Parse message + for ( ; *cp != '\0'; cp++) { + if (*cp != '\"') + continue; // Skip until " + cp++; // skip " + while (*cp != '\0' && *cp != '\"' && msglength-- > 1) + *msg++ = *cp++; + *msg = '\0'; + DEBUG_PRINT(">readSMS() msg", msg); + break; + } + + return a3gsSUCCESS; // OK +} + +//*************************** +// onSMSReceived +// +// @description +// Set call back function when SMS was receieved +// @return value +// 0 .. OK(always) +// @param +// handler : Call back function(Set) or NULL(Cancel) +// @note +// This function use attachInterrupt() and detachInterrupt() with interrupt number 0(D2). +// Interrupt mode is "LOW". +// It is necessary to call onSMSReceived() each time and to set up handler to use continuously. +//*************************** +int A3GS::onSMSReceived(void (*handler)(void)) +{ + if (handler == NULL) + _intin.fall(NULL); + else + _intin.fall(this, &A3GS::handleINT0); + + SMShandler = handler; + + return a3gsSUCCESS; // OK +} + +//*************************** +// httpGET +// +// @description +// Request HTTP/GET to server and port +// +// @return value +// 0 .. OK +// otherwise .. NG +// @param +// server : server name(ex. "www,google.com") +// port : port number(ex. 80) +// path : path(ex. service/index.html) +// result : [OUT] responce raw data(no escaped, '\0' terminated) +// resultlength ; "result" size(max MAX_RESULT_LENGTH) +// ssled : if true then use https(SSL), otherwise use http +// @note +// This function is synchronized. +// Support optional parameter "header" since @R3.0 +//*************************** +int A3GS::httpGET(const char* server, uint16_t port, const char* path, char* result, int resultlength, bool ssled, const char* header) +{ + int length = sizeof(gWorkBuffer); + int nbytes; + int c; //@R2.0 Change +//-- + // Send command line little by little + if (ssled) { + if (strlen(server) + strlen(path) + 8 > a3gsMAX_URL_LENGTH) + return 1; // NG -- Too long url + + sendData("$WG https://"); + sendData(server); + if (port != a3gsDEFAULT_PORT) { + char ports[6]; + sendData(":"); + sprintf(ports, "%u", port); + sendData(ports); + } + } + else { + if (strlen(server) + strlen(path) + 7 > a3gsMAX_URL_LENGTH) + return 1; // NG -- Too long url + + sendData("$WG http://"); + sendData(server); + if (port != a3gsDEFAULT_PORT) { + char ports[6]; + sendData(":"); + sprintf(ports, "%u", port); + sendData(ports); + } + } + + sendData(path); + + // Request with extra header --@R3.0 add + if (header != NULL) { + sendData(" \""); + sendData(header); + sendData("\""); + } + + sendCommand(""); // Go HTTP/GET request + + DEBUG_PRINT(">httpGET()", "REQ"); + + if (getResult(gWorkBuffer, &length, TIMEOUT_NETWORK)) + return 1; // NG -- maybe timeout + + DEBUG_PRINT(">httpGET()", gWorkBuffer); + // result's format: $WG=OK nbytes "response" + + // Parse response + if (strncmp(gWorkBuffer, "$WG=OK", 6)) + return 1; // NG -- Can't get response + + nbytes = atoi(gWorkBuffer + 7); + DEBUG_PRINT_NUM(">httpGET() nbytes", nbytes); + + // Copy response body into "result" and set "resultlength" + Timer millis; + millis.start(); + for (int n = 0; n < nbytes; n++) { + while (!iemSerial.readable()) { + // Wait until valid response + if (millis.read_ms() >= TIMEOUT_NETWORK) + return 2; // NG -- Timeout + } + c = iemSerial.getc(); + if (n < resultlength - 1) + result[n] = c; + } + discardUntil('\n'); // discard last '\n' -- @R2.0 Change + if (nbytes > resultlength - 1) //@R2.0 Change + result[resultlength - 1] = '\0'; + else + result[nbytes] = '\0'; + + return a3gsSUCCESS; // OK +} + +//*************************** +// httpPOST +// +// @discription +// Request HTTP/POST to server and port +// +// @return value +// 0 .. OK +// otherwise .. NG +// @param +// server : server name(ex. "www,google.com") +// port : port number(ex. 80) +// path : path(ex. service/index.html) +// header : header(without Content-Length, nul terminate, max MAX_HEADER_LENGTH) +// body : request body(nul terminate, max MAX_BODY_LENGTH) +// result : [OUT] responce raw data(no escaped) +// resultlength ; [OUT] "result" size(max MAX_RESULT_LENGTH) +// ssled : if true then use https(SSL), otherwise use http +// @note +// This function is synchronized. +//*************************** +int A3GS::httpPOST(const char* server, uint16_t port, const char* path, const char *header, const char *body, char* result, int* resultlength, bool ssled) +{ + int length = sizeof(gWorkBuffer); + int nbytes; + int c; //@R2.0 Change +//-- + if (strlen(body) > a3gsMAX_BODY_LENGTH) + return 1; // NG -- too long body + if (header != NULL && strlen(header) > a3gsMAX_HEADER_LENGTH) + return 1; // NG -- too long header + + // Send command line little by little + if (ssled) { + if (strlen(server) + strlen(path) + 8 > a3gsMAX_URL_LENGTH) + return 1; // NG -- Too long url + + sendData("$WP https://"); + sendData(server); + if (port != a3gsDEFAULT_PORT) { + char ports[6]; + sendData(":"); + sprintf(ports, "%u", port); + sendData(ports); + } + } + else { + if (strlen(server) + strlen(path) + 7 > a3gsMAX_URL_LENGTH) + return 1; // NG -- Too long url + + sendData("$WP http://"); + sendData(server); + if (port != a3gsDEFAULT_PORT) { + char ports[6]; + sendData(":"); + sprintf(ports, "%u", port); + sendData(ports); + } + } + + if (path[0] != '/') + sendData("/"); // for compatiblity old version + sendData(path); + + sendData(" \""); + + sendData(body); + + if (header != NULL && *header != '\0') { + sendData("\" \""); + sendData(header); + } + + sendCommand("\""); // Go command + + DEBUG_PRINT(">httpPOST()", "REQ"); + + if (getResult(gWorkBuffer, &length, TIMEOUT_NETWORK)) + return 1; // NG -- maybe timeout + + DEBUG_PRINT(">httpPOST()", gWorkBuffer); + // result's format: $WP=OK nbytes or $WP=NG errno + + // Parse response + if (strncmp(gWorkBuffer, "$WP=OK", 6)) + return 1; // NG -- Can't post or get response + + nbytes = atoi(gWorkBuffer + 7); + DEBUG_PRINT_NUM(">httpPOST() nbytes", nbytes); + + // Copy response body into "result" and set "resultlength" + Timer millis; + millis.start(); + for (int n = 0; n < nbytes; n++) { + while (!iemSerial.readable()) { + // Wait until valid response + if (millis.read_ms() >= TIMEOUT_NETWORK) + return 2; // NG -- Timeout + } + c = iemSerial.getc(); + if (n < *resultlength - 1) + result[n] = c; + } + discardUntil('\n'); // discard last '\n' -- @R2.0 Change + if (nbytes > *resultlength - 1) //@R2.0 Change + result[*resultlength - 1] = '\0'; + else { + result[nbytes] = '\0'; + *resultlength = nbytes; + } + + return a3gsSUCCESS; // OK +} + +//*************************** +// tweet +// +// @description +// Tweet a message +// +// @return value +// 0 .. OK +// otherwise .. NG +// @param +// token .. token from http://arduino-tweet.appspot.com/ +// msg .. message to tweet(in UTF-8) +// @note +// This function use cloud service on "arduino-tweet.appspot.com". +// Notice from this service: +// - The library uses this site as a proxy server for OAuth stuff. Your tweet may not be applied during maintenance of this site. +// - Please avoid sending more than 1 request per minute not to overload the server. +// - Twitter seems to reject repeated tweets with the same contenet (returns error 403). +// Use gWorkBuffer and destory it + +//*************************** +int A3GS::tweet(const char* token, const char* msg) +{ + int resultlength = sizeof(gWorkBuffer); +//-- + if (strlen(msg) > a3gsMAX_TWEET_LENGTH) + return 8; // Too long message. (@@ check by number of characters, not bytes) + + sprintf(gWorkBuffer, "token=%s&status=%s", token, msg); + + // request POST to http://arduino-tweet.appspot.com + return httpPOST("arduino-tweet.appspot.com", 80, "update", NULL, gWorkBuffer, gWorkBuffer, &resultlength); +} + +//*************************** +// getTime +// +// @description +// Get current date and time +// @return value +// 0 .. OK +// otherwise .. NG +// @param +// date : [OUT] current date(JST) ("YYYY/MM/DD" format) +// time : [OUT] current time(JST) ("HH:MM:SS" format) +// @note +// +//*************************** +int A3GS::getTime(char date[], char time[]) +{ + char responses[28]; // Format "$YT=OK 2012/03/18 13:28:25" + int length = sizeof(responses); +//-- + sendCommand("$YT"); // Send "Get Time" command + + if (getResult(responses, &length, TIMEOUT_LOCAL)) + return 1; // NG -- maybe timeout + + DEBUG_PRINT(">getTime()", responses); + + if (strncmp(responses, "$YT=OK", 6)) + return 1; // NG -- Can't get time + + // Parse response + strncpy(date, responses + 7, 10); + date[10] = '\0'; + + strncpy(time, responses + 18, 8); + time[8] = '\0'; + + return a3gsSUCCESS; // OK +} + +//*************************** +// getTime2 +// +// @description +// Get the current time as seconds since Jan 1 1970 +// @return value +// 0 .. OK +// otherwise .. NG +// @param +// seconds : [OUT] Current seconds since Jan 1 1970(JST) +// @noyte +// +//*************************** +int A3GS::getTime2(uint32_t& seconds) +{ + static const uint8_t monthDays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + char date[a3gsDATE_SIZE]; + char time[a3gsTIME_SIZE]; + uint8_t year, month, day, hour, minute, second; + uint32_t t; // total seconds from 1970/01/01 00:00:00 +//-- + // Get Current Time + if (getTime(date, time) != 0) + return 1; // NG -- can't get time, Failed. + + year = atoi(date) - 1970; + month = atoi(date+5); + day = atoi(date+8); + hour = atoi(time); + minute = atoi(time+3); + second = atoi(time+6); + + // Seconds from 1970 till 1 jan 00:00:00 of the given year + t = year * (SECS_PER_DAY * 365); + for (int y = 0; y < year; y++) { + if (LEAP_YEAR(y)) + t += SECS_PER_DAY; // add extra days for leap years + } + + // Add days for this year, months start from 1 + for (int m = 1; m < month; m++) { + if ((m == 2) && LEAP_YEAR(year)) + t += SECS_PER_DAY * 29; + else + t += SECS_PER_DAY * monthDays[m-1]; //monthDay array starts from 0 + } + t += (day - 1) * SECS_PER_DAY; + t += hour * SECS_PER_HOUR; + t += minute * SECS_PER_MIN; + t += second; + + seconds = t; + + return a3gsSUCCESS; // OK +} + +//*************************** +// getRSSI +// +// @description +// Get 3G RSSI +// @return value +// 0 .. OK +// 1 .. NG +// @param +// rssi : [OUT] rssi (dBm) +// @note +// +//*************************** +int A3GS::getRSSI(int& rssi) +{ + char responses[13]; // Format "$YR=OK -999" + int length = sizeof(responses); +//-- + sendCommand("$YR"); // Send "Get RSSI" command + + if (getResult(responses, &length, TIMEOUT_LOCAL)) + return 1; // NG -- maybe timeout + + DEBUG_PRINT(">getRSSI()", responses); + + // Parse response + rssi = atoi(responses + 7); + + return a3gsSUCCESS; // OK +} + +//*************************** +// getVersion +// +// @description +// Get Version +// @return value +// 0 .. OK +// 1 .. NG +// @param +// version : [OUT] version ("X.YY") +// @note +// +//*************************** +int A3GS::getVersion(char *version) +{ + char responses[13]; // Format "$YV=OK 9.99" + int length = sizeof(responses); +//-- + sendCommand("$YV"); // Send "Get Version" command + + if (getResult(responses, &length, TIMEOUT_LOCAL)) + return 1; // NG -- maybe timeout + + DEBUG_PRINT(">getVersion()", responses); + + // Copy version + strcpy(version, responses + 7); + + return a3gsSUCCESS; // OK +} + +//*************************** +// getLocation +// +// @description +// get Current Location from GPS and Network +// +// @return value +// 0 .. OK +// 1 .. NG(Bad parameters) +// otherwise .. NG(Can't locate position..) +// @param +// method .. method of locate(a3gsM) +// latitude .. [OUT] latitude +// longitude .. [OUT] longitude +// @note +// 10-180 Sec. required. +//*************************** +int A3GS::getLocation(int method, char* latitude, char* longitude) +{ + char *cp, responses[40]; // Format "$LG=OK lat lng" + int length = sizeof(responses); +//-- + *latitude = '\0'; + *longitude = '\0'; + + // Make command and send it + switch (method) { + case a3gsMPBASED : + sendCommand("$LG MSBASED"); // Default is method=MSBASED + break; + case a3gsMPASSISTED : + sendCommand("$LG MSASSISTED"); + break; + case a3gsMPSTANDALONE : + sendCommand("$LG STANDALONE"); + break; + default : + return 1; // bad method + } + + if (getResult(responses, &length, TIMEOUT_GPS)) + return 1; // NG -- maybe timeout + + DEBUG_PRINT(">getLocation()", responses); + + // parse response + if (! strncmp(responses, "$LG=NG", 6)) + return 1; // NG -- Can't locate + + // Parse lattitude (assume enough space to store latitude) + for (cp = responses+7; *cp != '\0'; cp++) { + while (ISDIGIT(*cp) || *cp == '.') + *latitude++ = *cp++; + *latitude = '\0'; + DEBUG_PRINT(">getLocation() lat", latitude); + break; + } + + // Skip spaces + while (*cp != '\0' && ! ISDIGIT(*cp)) + cp++; + + // Parse longitude (assume enough space to store longitude) + for ( ; *cp != '\0'; cp++) { + while (ISDIGIT(*cp) || *cp == '.') + *longitude++ = *cp++; + *longitude = '\0'; + DEBUG_PRINT(">getLocation() lng", longitude); + break; + } + + return a3gsSUCCESS; // OK +} + +//*************************** +// setDefaultProfile +// +// @description +// Set default profile(APN) number +// @return value +// 0 .. OK +// 1 .. NG(Bad parameters) +// @param +// profileNum : profile number(1..a3gsMAX_PROFILE_NUMBER) +// @note +// +//*************************** +int A3GS::setDefaultProfile(int profileNum) +{ + char responses[20]; // Format "$PS=OK" + char commands[20]; // Format "$PS 99" + int length = sizeof(responses); +//-- + if (profileNum < 1 || a3gsMAX_PROFILE_NUMBER < profileNum) + return 1; // NG -- Bad parameter + + sprintf(commands, "$PS %d", profileNum); + sendCommand(commands); // Send "Set Profile" command + + if (getResult(responses, &length, TIMEOUT_LOCAL)) + return 1; // NG -- maybe timeout + + DEBUG_PRINT(">setDefaultProfile()", responses); + + // parse response + if (! strncmp(responses, "$PS=NG", 6)) + return 1; // NG -- Can't set prfoile number + + return a3gsSUCCESS; // OK +} + +//*************************** +// getDefaultProfile +// +// @description +// Get default profile(APN) number +// @return value +// 0 .. OK +// 1 .. NG +// @param +// profileNum : [OUT] profile number(1..a3gsMAX_PROFILE_NUMBER) +// @note +// +//*************************** +int A3GS::getDefaultProfile(int* profileNum) +{ + char responses[20]; // Format "$PR=OK 99\n" + int length = sizeof(responses); +//-- + sendCommand("$PR"); // Send "Read Profile" command + + if (getResult(responses, &length, TIMEOUT_LOCAL)) + return 1; // NG -- maybe timeout + + DEBUG_PRINT(">getDefaultProfile()", responses); + + // parse response + *profileNum = atoi(responses + 7); + + return a3gsSUCCESS; // Succeeded +} + +//*************************** +// connectTCP +// +// @description +// Connect to server with TCP/IP connection +// @return value +// 0 .. OK +// 1 .. NG +// @param +// server : server name or IP address(ex. "www,google.com", "192.161.10.1") +// port : port number(ex. 80) +// @note +// +//*************************** +int A3GS::connectTCP(const char* server, int port) +{ + char responses[30]; // FORMAT: "$TC=OK\n" or "$TC=NG errno [info]\n" + int length = sizeof(responses); +//-- + // Check parameter size + if (strlen(server) > a3gsMAX_HOST_LENGTH) + return 1; // NG -- too long host name + // Make command and send it + sprintf(gWorkBuffer, "$TC %s %d", server, port); + sendCommand(gWorkBuffer); + + if (getResult(responses, &length, TIMEOUT_NETWORK)) + return 1; // NG -- maybe timeout + + DEBUG_PRINT(">connectTCP()", responses); + + // parse response + if (! strncmp(responses, "$TC=NG", 6)) + return 1; // NG -- Can't connect + + // Change status + _status = TCPCONNECTEDCLIENT; + + return a3gsSUCCESS; // OK +} + +//*************************** +// disconnectTCP +// +// @description +// Disconnect from server with current TCP/IP connection +// @return value +// 0 .. OK +// 1 .. NG +// @param +// none +// @note +// +//*************************** +int A3GS::disconnectTCP() +{ + char responses[30]; // FORMAT: "$TD=OK\n" or "$TD=NG errno [info]\n" + int length = sizeof(responses); +//-- + // Send command + sendCommand("$TD"); + + if (getResult(responses, &length, TIMEOUT_NETWORK)) + return 1; // NG -- maybe timeout + + DEBUG_PRINT(">disconnectTCP()", responses); + + // parse response + if (! strncmp(responses, "$TD=NG", 6)) + return 1; // NG -- Can't connect + + // Change status + _status = READY; + + return a3gsSUCCESS; // OK +} + +//*************************** +// write +// +// @description +// Write byte into current TCP/IP connection +// @return value +// -1 .. NG (Error) +// 1 .. OK +// @param +// c : byte data to write +// @note +// R2.3 bug fix(binary data escaping) +//*************************** +int A3GS::write(uint8_t c) +{ + char responses[30]; // FORMAT: "$TW=OK nbytes\n" or "$TW=NG errno [info]\n" + int length = sizeof(responses); +//-- + // Make command and send it + sendData("$TW \""); + if (c < 0x20) { + char escaped[6]; + sprintf(escaped, "$x%02x", c); + iemSerial.puts(escaped); + } + // @R2.3 add -begin- + else if (c == '"') { + iemSerial.puts("$\""); + } + else if (c == '$') { + iemSerial.puts("$$"); + } + // @R2.3 add -end- + else { + iemSerial.putc(c); + } + sendCommand("\""); + + if (getResult(responses, &length, TIMEOUT_NETWORK)) + return -1; // NG -- maybe timeout + + DEBUG_PRINT(">write()", responses); + + // parse response + if (! strncmp(responses, "$TW=NG", 6)) + return -1; // NG -- Can't connect + + int nbytes = atoi(responses + 7); + + return nbytes; // OK +} + +//*************************** +// write +// +// @description +// Write string into current TCP/IP connection +// @return value +// -1 .. NG (Error) +// 0 < .. OK (= wrote bytes) +// @param +// str : string(= '\0' terminated byte array) to write +// @note +// "str" must be encoded by $ escape sequence +//*************************** +int A3GS::write(const char* str) +{ + char responses[30]; // FORMAT: "$TW=OK nbytes" or "$TW=NG errno [info]\n" + int length = sizeof(responses); +//-- + if (strlen(str) > a3gsMAX_DATA_LENGTH) + return -1; // NG -- too large data + + // Make command and send it + sendData("$TW \""); + sendData(str); + sendCommand("\""); + + if (getResult(responses, &length, TIMEOUT_NETWORK)) + return -1; // NG -- maybe timeou\t + + DEBUG_PRINT(">write()", responses); + + // parse response + if (! strncmp(responses, "$TW=NG", 6)) + return -1; // NG -- Can't connect + + int nbytes = atoi(responses + 7); + + return nbytes; // OK +} + +//*************************** +// write +// +// @description +// Write byte data into current TCP/IP connection +// @return value +// -1 .. NG (Error) +// 0 < .. OK (= wrote bytes) +// @param +// buffer : data to write(byte array) +// sz : data size(in byte) +// @note +// R2.3 bug fix(binary data escaping) +//*************************** +int A3GS::write(const uint8_t* buffer, size_t sz) +{ + char responses[30]; // FORMAT: "$TW=OK nbytes\n" or "$TW=NG errno [info]\n" + int length = sizeof(responses); +//-- + if (sz > (size_t)a3gsMAX_DATA_LENGTH) + return -1; // NG -- too large data + + // Make command and send it + sendData("$TW \""); + while (sz-- > 0) { + if (*buffer < 0x20) { + char escaped[6]; + sprintf(escaped, "$x%02x", *buffer); + iemSerial.puts(escaped); + } + // @R2.3 add -begin- + else if (*buffer == '"') { + iemSerial.puts("$\""); + } + else if (*buffer == '$') { + iemSerial.puts("$$"); + } + // @R2.3 add -end- + else { + iemSerial.putc((char)*buffer); + } + buffer++; + } + sendCommand("\""); + + if (getResult(responses, &length, TIMEOUT_NETWORK)) + return -1; // NG -- maybe timeout + + DEBUG_PRINT(">write()", responses); + + // parse response + if (! strncmp(responses, "$TW=NG", 6)) + return -1; // NG -- Can't connect + + int nbytes = atoi(responses + 7); + + return nbytes; // OK +} + +//*************************** +// read +// +// @description +// Read data from current TCP/IP connection +// @return value +// -2 .. NG (Closed connection by other side) +// -1 .. NG (Error) +// 0 .. OK (No data) +// 0 < .. OK (= read bytes) +// @param +// result : [OUT] read data(byte array, not '\0' terminated) +// resultlength : data length(in byte) +// @note +// R2.3 fix return value bug +// This function leaves for compatibility +//*************************** +int A3GS::read(char* result, int resultlength) +{ + int length = sizeof(gWorkBuffer); + int c; //@R2.0 Change +//-- + if (resultlength > a3gsMAX_DATA_LENGTH) + return -1; // NG -- Bad parameter + + // Make command and send it + sprintf(gWorkBuffer, "$TR %d", resultlength); + sendCommand(gWorkBuffer); + + if (getResult(gWorkBuffer, &length, TIMEOUT_NETWORK)) + return (-1); // NG -- can't read + + DEBUG_PRINT(">read()", gWorkBuffer); + + // Parse response + if (! strncmp(gWorkBuffer, "$TR=NG", 6)) { + int errno = atoi(gWorkBuffer + 7); + switch (errno) { + case 635 : // Connection closed + case 636 : + return (-2); + default : // Other error + return (-1); + } + } + + int nbytes = atoi(gWorkBuffer + 7); + DEBUG_PRINT_NUM(">read() nbytes", nbytes); + + // Copy response body into "result" and set "resultlength" + for (int n = 0; n < nbytes; ) { + while (!iemSerial.readable()) + ; // read until valid response + c = iemSerial.getc(); + if (n < resultlength - 1) + result[n] = c; + n++; + } + discardUntil('\n'); // discard last '\n' -- @R2.0 Change + + if (nbytes > resultlength - 1) { //@R2.0 Change + result[resultlength - 1] = '\0'; + return (resultlength - 1); // OK + } + else { + result[nbytes] = '\0'; + return nbytes; // OK + } +} + +//*************************** +// read +// +// @description +// Read (binary) data from current TCP/IP connection +// @return value +// -2 .. NG (Closed connection by other side) +// -1 .. NG (Error) +// 0 .. OK (No data) +// 0 < .. OK (= read bytes) +// @param +// buffer : [OUT] read data(byte array, not '\0' terminated) +// sz : binary data size(in byte) +// @note +// R2.3 Add this function +//*************************** +int A3GS::read(uint8_t* buffer, size_t sz) +{ + int length = sizeof(gWorkBuffer); + int c; +//-- + if (sz > (size_t)a3gsMAX_DATA_LENGTH) + return -1; // NG -- Bad parameter + + // Make command and send it + sprintf(gWorkBuffer, "$TR %d", sz); + sendCommand(gWorkBuffer); + + if (getResult(gWorkBuffer, &length, TIMEOUT_NETWORK)) + return (-1); // NG -- can't read + + DEBUG_PRINT(">read()", gWorkBuffer); + + // Parse response + if (! strncmp(gWorkBuffer, "$TR=NG", 6)) { + int errno = atoi(gWorkBuffer + 7); + switch (errno) { + case 635 : // Connection closed + case 636 : + return (-2); + default : // Other error + return (-1); + } + } + + size_t nbytes = atoi(gWorkBuffer + 7); + DEBUG_PRINT_NUM(">read() nbytes", nbytes); + + // Copy response body into "result" and set "resultlength" + size_t n; + for (n = 0; n < nbytes; n++) { + while (!iemSerial.readable()) + ; // read until valid response + c = iemSerial.getc(); + if (n < sz) + buffer[n] = (uint8_t)c; + } + + discardUntil('\n'); // discard last '\n' + + return (int)((n < sz) ? n : sz); // OK +} + +//*************************** +// read +// +// @description +// Read byte from current TCP/IP connection +// @return value +// -2 .. NG (Closed connection by other side) +// -1 .. NG (Error) +// -3 .. OK (No data) +// 0..0xFF .. OK (= read byte) +// @param +// none +// @note +// This function is synchronized operation. +// Change return value type at @R2.0 +//*************************** +int A3GS::read(void) +{ + int length = sizeof(gWorkBuffer); + int c; //@R2.0 Change +//-- + // Send command + sendCommand("$TR 1"); + + if (getResult(gWorkBuffer, &length, TIMEOUT_NETWORK)) + return (-1); // NG -- can't read + + DEBUG_PRINT(">read()", gWorkBuffer); + + // Parse response + if (! strncmp(gWorkBuffer, "$TR=NG", 6)) { + int errno = atoi(gWorkBuffer + 7); + switch (errno) { + case 635 : // Connection closed + case 636 : + return (-2); + default : // Other error + return (-1); + } + } + + size_t nbytes = atoi(gWorkBuffer + 7); + DEBUG_PRINT_NUM(">read() nbytes", nbytes); + + if (nbytes == 1) { + while (!iemSerial.readable()) + ; // read valid response + c = iemSerial.getc(); + } + else // if (nbytes == 0) + c = -3; // NG -- no data + + discardUntil('\n'); // discard last '\n' -- @R2.0 Change + + return c; // OK +} + +//*************************** +// put +// +// @description +// Put data to non-volatile storage in 3G shield +// @return value +// -1 .. NG (Error) +// 0 .. OK +// @param +// storageNum : [IN] Storage number (1..a3gsMAX_STORAGE_NUMBER) +// buffer : [IN] Put data +// sz : [IN] size of data (in bytes) +// @note +// @3.0 add +//*************************** +int A3GS::put(int storageNum, uint8_t *buffer, size_t sz) +{ + char responses[30]; // FORMAT: "$RW=OK nbytes\n" or "$RW=NG errno [info]\n" + int length = sizeof(responses); +//-- + if (storageNum < 0 || storageNum > a3gsMAX_STORAGE_NUMBER) + return a3gsERROR; // NG -- Bad parameter + + if (sz < 1 || sz > (size_t)a3gsMAX_STORAGE_LENGTH) + return a3gsERROR; // NG -- too large data + + // Make command and send it + sprintf(responses, "$RW %d \"", storageNum); + sendData(responses); + while (sz-- > 0) { + if (*buffer < 0x20) { + char escaped[6]; + sprintf(escaped, "$x%02x", *buffer); + iemSerial.puts(escaped); + } + else if (*buffer == '"') + iemSerial.puts("$\""); + else if (*buffer == '$') + iemSerial.puts("$$"); + else + iemSerial.putc(*buffer); + buffer++; + } + sendCommand("\""); // execute $RW command + + if (getResult(responses, &length, TIMEOUT_NETWORK)) + return a3gsERROR; // NG -- maybe timeout + + DEBUG_PRINT(">put()", responses); + + // parse response + if (! strncmp(responses, "$RW=NG", 6)) + return a3gsERROR; // NG -- Can't connect + + return a3gsSUCCESS; // OK +} + +//*************************** +// get +// +// @description +// Get data from non-volatile storage in 3G shield +// @return value +// -1 .. NG (Error) +// 0..a3gsMAX_STORAGE_LENGTH .. OK (length of data to get) +// @param +// storageNum : [IN] Storage number (1..a3gsMAX_STORAGE_NUMBER) +// buffer : [OUT] Got data space +// sz : [OUT] size of data (in bytes) +// @note +// @3.0 add +//*************************** +int A3GS::get(int storageNum, uint8_t *buffer, size_t sz) +{ + int length = sizeof(gWorkBuffer); + int c; +//-- + if (storageNum < 0 || storageNum > a3gsMAX_STORAGE_NUMBER) + return a3gsERROR; // NG -- Bad parameter + + if (sz > (size_t)a3gsMAX_STORAGE_LENGTH) + return a3gsERROR; // NG -- Bad parameter + + // Make command and send it + sprintf(gWorkBuffer, "$RR %d", storageNum); + sendCommand(gWorkBuffer); + + if (getResult(gWorkBuffer, &length, TIMEOUT_NETWORK)) + return a3gsERROR; // NG -- can't read + + DEBUG_PRINT(">get()", gWorkBuffer); + + // Parse response + if (! strncmp(gWorkBuffer, "$RR=NG", 6)) + return a3gsERROR; // NG -- can't read + + size_t nbytes = atoi(gWorkBuffer + 7); + DEBUG_PRINT_NUM(">get() nbytes", nbytes); + + // Copy response body into "result" and set "resultlength" + size_t n; + for (n = 0; n < nbytes; n++) { + while (!iemSerial.readable()) + ; // read until valid response + c = iemSerial.getc(); + if (n < sz) + buffer[n] = (uint8_t)c; + } + discardUntil('\n'); // discard last '\n' + + return (int)((n < sz) ? n : sz); // OK +} + +//*************************** +// updateProfile +// +// @description +// Update profile with encrypted data +// @return value +// -1 .. NG +// 0 .. OK +// @param +// encryptedProfile : [IN] Encrypted profile +// sz : [IN] bytes of encrypted profile +// @note +// @3.0 add +//*************************** +int A3GS::updateProfile(const uint8_t *encryptedProfile, int sz) +{ + int length = sizeof(gWorkBuffer); +//-- + // Make command and send it + sendData("$YD - \""); + for (char *p = (char *)encryptedProfile; sz-- > 0; p++) { + if (*p < 0x20) { + char escaped[6]; + sprintf(escaped, "$x%02x", (uint8_t)*p); + iemSerial.puts(escaped); +// Serial.print(escaped); + } + else if (*p == '"') { + iemSerial.puts("$\""); +// Serial.print("$\""); + } + else if (*p == '$') { + iemSerial.puts("$$"); +// Serial.print("$$"); + } + else { + iemSerial.putc(*p); +// Serial.print((char)*p); + } + } + sendCommand("\""); + + if (getResult(gWorkBuffer, &length, TIMEOUT_LOCAL)) + return -1; // NG -- maybe timeout + + // parse response + if (! strncmp(gWorkBuffer, "$YD=NG", 6)) + return -1; // NG -- Can't do + + return 0; // OK +} + +//*************************** +// encryptString +// +// @description +// Encrypt string with password +// @return value +// -1 .. NG +// 0 .. OK +// @param +// password : [IN] Password to encrypt +// s : [IN] String to encrypt +// @note +// @3.0 add +//*************************** +int A3GS::encryptString(const char *password, const char *s) +{ + int length = sizeof(gWorkBuffer); +//-- + // Make command and send it + sendData("$YY "); + sendData(password); + sendData(" \""); + sendData(s); + sendCommand("\""); + + if (getResult(gWorkBuffer, &length, TIMEOUT_LOCAL)) + return -1; // NG -- maybe timeout + + // parse response + if (! strncmp(gWorkBuffer, "$YY=NG", 6)) + return -1; // NG -- Can't encrypt + + size_t nbytes = atoi(gWorkBuffer + 7); + DEBUG_PRINT_NUM(">encrypt() nbytes", nbytes); + + printf(">>"); + int c; + for (int n = 0; n < (int)nbytes; n++) { + while (!iemSerial.readable()) + ; // read until valid response + c = iemSerial.getc(); + printf("\\x"); + printf("%02x", c); + } + printf("<<\r\n"); + + discardUntil('\n'); // discard last '\n' + + return 0; // OK +} + + +//*** +// Private methods +//*** + +// sendCommand() -- send command to iem with \n +void A3GS::sendCommand(const char* cmd) +{ + // Send command to IEM with '\n' + iemSerial.puts(cmd); + iemSerial.putc('\n'); + DEBUG_PRINT("<sendCommand()", cmd); +} + +// sendData() -- send data to iem without \n +void A3GS::sendData(const char* data) +{ + // Send data to IEM without '\n' + iemSerial.puts(data); + DEBUG_PRINT("<sendData()", data); +} + +// discardUntl() -- discard characters from iemSerial until match specified character +void A3GS::discardUntil(const char match) +{ + int c; //@R2.0 Change + Timer millis; + bool done = false; +//-- + millis.start(); + while (! done) { + if (millis.read_ms() >= TIMEOUT_LOCAL) { + DEBUG_PRINT(">discardUntil()", "TIMEOUT"); + break; // Timeout ! + } + + if (!iemSerial.readable()) + continue; // discard until valid response -- @R2.1 Change + + c = iemSerial.getc(); + if (c == match) + done = true; + } +} + +// getResult() -- get result from IEM +int A3GS::getResult(char *buf, int *len, uint32_t timeout) +{ + Timer millis; + bool completed = false; + int length = 0; + millis.start(); + while (! completed) { + if (millis.read_ms() >= timeout) { + DEBUG_PRINT(">getResult()", "TIMEOUT"); + return 1; // NG -- Timeout + } + if (!iemSerial.readable()) + continue; + int c = iemSerial.getc(); + if (c >= 0x20 && c < 0x7f) { + DBG("%c", c); + } else { + DBG("_%02x", c); + } + if (c == 0x0a) { // end of line + if (buf[0] == '$') + completed = true; // got result + else + length = 0; // got status, so retry + } + else if (length < *len - 1) + buf[length++] = c; + } + buf[length] = '\0'; + *len = length; + + DEBUG_PRINT("<getResult", buf); + + return 0; // OK +} + +// handleINT0() -- Interrupt Service Routine(ISR) of INT0 +void A3GS::handleINT0(void) +{ + // disable INT0 + _intin.fall(NULL); + + (*SMShandler)(); // Call user handler(You can use other interrupts(UART, millis()..)) + + // Clear hander + SMShandler = NULL; +} + +// END OF a3gs.cpp +