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
a3gs.cpp
- Committer:
- phsfan
- Date:
- 2015-03-10
- Revision:
- 0:ca471c239d5f
File content as of revision 0:ca471c239d5f:
//*********************************************************** // 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