PHS module APM-002 library. see: https://developer.mbed.org/users/phsfan/notebook/abitusbmodem/

Dependencies:   Socket lwip-sys lwip

Fork of AbitUSBModem by phs fan

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers PPPIPInterface.cpp Source File

PPPIPInterface.cpp

00001 /* PPPIPInterface.cpp */
00002 /* Modified by 2015 phsfan
00003  *  for ABIT SMA-01
00004  */
00005 /* Copyright (C) 2012 mbed.org, MIT License
00006  *
00007  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
00008  * and associated documentation files (the "Software"), to deal in the Software without restriction,
00009  * including without limitation the rights to use, copy, modify, merge, publish, distribute,
00010  * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
00011  * furnished to do so, subject to the following conditions:
00012  *
00013  * The above copyright notice and this permission notice shall be included in all copies or
00014  * substantial portions of the Software.
00015  *
00016  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
00017  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00018  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
00019  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00020  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00021  */
00022 
00023 #define __DEBUG__ 0
00024 #ifndef __MODULE__
00025 #define __MODULE__ "PPPIPInterface.cpp"
00026 #endif
00027 
00028 #include "core/fwk.h"
00029 #include "rtos.h"
00030 
00031 #include <cstdio>
00032 using std::sscanf;
00033 
00034 #include "PPPIPInterface.h"
00035 
00036 #define DEFAULT_TIMEOUT 10000
00037 
00038 #define MSISDN "0570570711##64"
00039 
00040 #define CONNECT_CMD "ATD" MSISDN "\x0D"
00041 #define EXPECTED_RESP CONNECT_CMD "\x0D" "\x0A" "CONNECT" "\x0D" "\x0A"
00042 #define EXPECTED_RESP_DATARATE CONNECT_CMD "\x0D" "\x0A" "CONNECT %d" "\x0D" "\x0A"
00043 #define EXPECTED_RESP_MIN_LEN 32
00044 #define OK_RESP "\x0D" "\x0A" "OK" "\x0D" "\x0A"
00045 #define ESCAPE_SEQ "+++"
00046 #define HANGUP_CMD "ATH" "\x0D"
00047 #define NO_CARRIER_RESP "\x0D" "\x0A" "NO CARRIER" "\x0D" "\x0A"
00048 extern "C" {
00049 #include "lwip/ip_addr.h"
00050 #include "lwip/inet.h"
00051 #include "lwip/err.h"
00052 #include "lwip/dns.h"
00053 
00054 #include "netif/ppp/ppp.h"
00055 }
00056 
00057 PPPIPInterface::PPPIPInterface(
00058       IOStream* pStream,
00059       IOStream* atStream,
00060       ATCommandsInterface* pIf,
00061       bool hangupViaATPort
00062    ) :
00063    LwIPInterface(),
00064    m_pIf(pIf),
00065    m_linkStatusSphre(1),
00066    m_pppErrCode(0),
00067    m_pStream(pStream),
00068    m_atStream(atStream),
00069    m_streamAvail(true),
00070    m_hangupViaATPort(hangupViaATPort),
00071    m_pppd(-1)
00072 {
00073 
00074     m_linkStatusSphre.wait();
00075 }
00076 
00077 /*virtual*/ PPPIPInterface::~PPPIPInterface()
00078 {
00079 
00080 }
00081 
00082 void PPPIPInterface::setHangupViaATPort(bool val) {
00083    m_hangupViaATPort = val;
00084 }
00085 
00086 /*virtual*/ int PPPIPInterface::init() //Init PPP-specific stuff, create the right bindings, etc
00087 {
00088     DBG("Initializing LwIP");
00089     LwIPInterface::init(); //Init LwIP, NOT including PPP
00090     DBG("Initializing PPP");
00091     pppInit();
00092     DBG("Done");
00093     return OK;
00094 }
00095 
00096 int PPPIPInterface::setup(const char* user, const char* pw)
00097 {
00098     DBG("Configuring PPP authentication method");
00099     pppSetAuth(PPPAUTHTYPE_ANY, user, pw);
00100     DBG("Done");
00101     return OK;
00102 }
00103 
00104 /*virtual*/ int PPPIPInterface::connect()
00105 {
00106     int ret;
00107     char buf[40];
00108     size_t len;
00109     DBG("Trying to connect with PPP");
00110 
00111     cleanupLink();
00112     Thread::wait(1000);
00113 
00114     DBG("Sending %s", CONNECT_CMD);
00115 
00116     ret = m_pStream->write((uint8_t*)CONNECT_CMD, strlen(CONNECT_CMD), osWaitForever);
00117     if( ret != OK ) {
00118         return NET_UNKNOWN;
00119     }
00120 
00121     DBG("Expect %s", EXPECTED_RESP);
00122 
00123     Thread::wait(100);
00124     len = 0;
00125     size_t readLen;
00126     ret = m_pStream->read((uint8_t*)buf + len, &readLen, sizeof(buf) - 1, DEFAULT_TIMEOUT);
00127     if( ret != OK ) {
00128         return NET_UNKNOWN;
00129     }
00130     len += readLen;
00131     while( (len < EXPECTED_RESP_MIN_LEN) || (buf[len-1] != LF) ) {
00132         Thread::wait(100);
00133         ret = m_pStream->read((uint8_t*)buf + len, &readLen, sizeof(buf) - len - 1, DEFAULT_TIMEOUT);
00134         if( ret != OK ) {
00135             break;
00136 //            return NET_UNKNOWN;
00137         }
00138         len += readLen;
00139     }
00140 
00141     buf[len]=0;
00142 
00143     DBG("Got %s[len %d]", buf, len);
00144 
00145     int datarate = 0;
00146     if( (sscanf( buf, EXPECTED_RESP_DATARATE, &datarate ) != 1) && (strcmp(EXPECTED_RESP, buf) != 0) ) {
00147         //Discard buffer
00148         do { //Clear buf
00149             ret = m_pStream->read((uint8_t*)buf, &len, 32, 0);
00150         } while( (ret == OK) && (len > 0) );
00151         return NET_CONN;
00152     }
00153 
00154     DBG("Transport link open");
00155     if(datarate != 0) {
00156         DBG("Datarate: %d bps", datarate);
00157     }
00158     m_linkStatusSphre.wait(0);
00159     if((m_pppd != -1) && (m_pppErrCode == 0)) { //Already connected
00160         return NET_INVALID;
00161     }
00162 
00163     ret = pppOverSerialOpen(this, PPPIPInterface::linkStatusCb, this);
00164     if(ret < 0) {
00165         switch(ret) {
00166             case PPPERR_OPEN:
00167             default:
00168                 return NET_FULL; //All available resources are already used
00169         }
00170     }
00171     m_pppd = ret; //PPP descriptor
00172     m_linkStatusSphre.wait(); //Block indefinitely; there should be a timeout there
00173     if(m_pppErrCode != PPPERR_NONE) {
00174         m_pppd = -1;
00175     }
00176     switch(m_pppErrCode) {
00177         case PPPERR_NONE: //Connected OK
00178             return OK;
00179         case PPPERR_CONNECT: //Connection lost
00180             return NET_INTERRUPTED;
00181         case PPPERR_AUTHFAIL: //Authentication failed
00182             return NET_AUTH;
00183         case PPPERR_PROTOCOL: //Protocol error
00184             return NET_PROTOCOL;
00185         default:
00186             return NET_UNKNOWN;
00187     }
00188 }
00189 
00190 /*virtual*/ int PPPIPInterface::disconnect()
00191 {
00192     DBG("disconnect called");
00193     int ret = m_linkStatusSphre.wait(0);
00194     if(ret > 0) { //Already disconnected?
00195         m_pppd = -1; //Discard PPP descriptor
00196         switch(m_pppErrCode) {
00197             case PPPERR_CONNECT: //Connection terminated
00198             case PPPERR_AUTHFAIL: //Authentication failed
00199             case PPPERR_PROTOCOL: //Protocol error
00200             case PPPERR_USER:
00201                 return OK;
00202             default:
00203                 return NET_UNKNOWN;
00204         }
00205     } else {
00206         if(m_pppd == -1) {
00207             return NET_INVALID;
00208         }
00209         pppClose(m_pppd);
00210         do {
00211             m_linkStatusSphre.wait(); //Block indefinitely; there should be a timeout there
00212             DBG("Received PPP err code %d", m_pppErrCode);
00213         } while(m_pppErrCode != PPPERR_USER);
00214         m_pppd = -1; //Discard PPP descriptor
00215     }
00216     
00217     if(!m_hangupViaATPort) {
00218        DBG("Sending %s", ESCAPE_SEQ);
00219        Thread::wait(1000);
00220        ret = m_pStream->write((uint8_t*)ESCAPE_SEQ, strlen(ESCAPE_SEQ), osWaitForever);
00221        Thread::wait(1000);
00222        if( ret != OK ) {
00223           return NET_UNKNOWN;
00224        }
00225     }
00226 
00227     cleanupLink();
00228 
00229     return OK;
00230 }
00231 
00232 
00233 int PPPIPInterface::cleanupLink()
00234 {
00235     int ret;
00236     char buf[32];
00237     size_t len;
00238 
00239     do { //Clear buf
00240         ret = m_pStream->read((uint8_t*)buf, &len, 32, 100);
00241         if(ret == OK) {
00242             buf[len] = '\0';
00243             DBG("Got %s", buf);
00244         }
00245     } while( (ret == OK) && (len > 0) );
00246     
00247     
00248     DBG("Sending %s", HANGUP_CMD);
00249     
00250     // set the port to send the hangup command to, and disable AT thread if necessary
00251     IOStream *hangupPort = m_pStream;
00252     if(m_hangupViaATPort) {
00253        m_pIf->pause();
00254        hangupPort = m_atStream;
00255     }
00256     
00257     
00258     ret = hangupPort->write((uint8_t*)HANGUP_CMD, strlen(HANGUP_CMD), osWaitForever);
00259     if( ret != OK ) {
00260         return NET_UNKNOWN;
00261     }
00262 
00263     size_t readLen;
00264 
00265     //Hangup
00266     DBG("Expect %s", HANGUP_CMD);
00267 
00268     len = 0;
00269     while( len < strlen(HANGUP_CMD) ) {
00270         ret = hangupPort->read((uint8_t*)buf + len, &readLen, strlen(HANGUP_CMD) - len, 100);
00271         if( ret != OK ) {
00272             break;
00273         }
00274         len += readLen;
00275         /////
00276         buf[len]=0;
00277         DBG("Got %s", buf);
00278     }
00279 
00280     buf[len]=0;
00281 
00282     DBG("Got %s[len %d]", buf, len);
00283 
00284     //OK response
00285     DBG("Expect %s", OK_RESP);
00286 
00287     len = 0;
00288     while( len < strlen(OK_RESP) ) {
00289         ret = hangupPort->read((uint8_t*)buf + len, &readLen, strlen(OK_RESP) - len, 100);
00290         if( ret != OK ) {
00291             break;
00292         }
00293         len += readLen;
00294         /////
00295         buf[len]=0;
00296         DBG("Got %s", buf);
00297     }
00298     
00299     
00300 
00301     buf[len]=0;
00302 
00303     DBG("Got %s[len %d]", buf, len);
00304     
00305     // restart AT thread
00306     if(m_hangupViaATPort) {
00307        m_pIf->restart();
00308     }
00309     
00310     //NO CARRIER event
00311     DBG("Expect %s", NO_CARRIER_RESP);
00312 
00313     len = 0;
00314     while( len < strlen(NO_CARRIER_RESP) ) {
00315         ret = m_pStream->read((uint8_t*)buf + len, &readLen, strlen(NO_CARRIER_RESP) - len, 100);
00316         if( ret != OK ) {
00317             break;
00318         }
00319         len += readLen;
00320         /////
00321         buf[len]=0;
00322         DBG("Got %s", buf);
00323     }
00324 
00325     buf[len]=0;
00326 
00327     DBG("Got %s[len %d]", buf, len);
00328 
00329     do { //Clear buf
00330         ret = m_pStream->read((uint8_t*)buf, &len, 32, 100);
00331         if(ret == OK) {
00332             buf[len] = '\0';
00333             DBG("Got %s", buf);
00334         }
00335     } while( (ret == OK) && (len > 0) );
00336 
00337 
00338     return OK;
00339 }
00340 
00341 /*static*/ void PPPIPInterface::linkStatusCb(void *ctx, int errCode, void *arg) //PPP link status
00342 {
00343     PPPIPInterface* pIf = (PPPIPInterface*)ctx;
00344     struct ppp_addrs* addrs = (struct ppp_addrs*) arg;
00345 
00346     switch(errCode) {
00347         case PPPERR_NONE:
00348             WARN("Connected via PPP.");
00349             DBG("Local IP address: %s", inet_ntoa(addrs->our_ipaddr));
00350             DBG("Netmask: %s", inet_ntoa(addrs->netmask));
00351             DBG("Remote IP address: %s", inet_ntoa(addrs->his_ipaddr));
00352             DBG("Primary DNS: %s", inet_ntoa(addrs->dns1));
00353             DBG("Secondary DNS: %s", inet_ntoa(addrs->dns2));
00354             //Setup DNS
00355             if (addrs->dns1.addr != 0) {
00356                 dns_setserver(0, (struct ip_addr*)&(addrs->dns1));
00357             }
00358             if (addrs->dns2.addr != 0) {
00359                 dns_setserver(1, (struct ip_addr*)&(addrs->dns1));
00360             }
00361 
00362             pIf->setConnected(true);
00363             pIf->setIPAddress(inet_ntoa(addrs->our_ipaddr));
00364             break;
00365         case PPPERR_CONNECT: //Connection lost
00366             WARN("Connection lost/terminated");
00367             pIf->setConnected(false);
00368             break;
00369         case PPPERR_AUTHFAIL: //Authentication failed
00370             WARN("Authentication failed");
00371             pIf->setConnected(false);
00372             break;
00373         case PPPERR_PROTOCOL: //Protocol error
00374             WARN("Protocol error");
00375             pIf->setConnected(false);
00376             break;
00377         case PPPERR_USER:
00378             WARN("Disconnected by user");
00379             pIf->setConnected(false);
00380             break;
00381         default:
00382             WARN("Unknown error (%d)", errCode);
00383             pIf->setConnected(false);
00384             break;
00385     }
00386 
00387     pIf->m_linkStatusSphre.wait(0); //If previous event has not been handled, "delete" it now
00388     pIf->m_pppErrCode = errCode;
00389     pIf->m_linkStatusSphre.release();
00390 }
00391 
00392 //LwIP PPP implementation
00393 extern "C"
00394 {
00395 
00396     /**
00397      * Writes to the serial device.
00398      *
00399      * @param fd serial device handle
00400      * @param data pointer to data to send
00401      * @param len length (in bytes) of data to send
00402      * @return number of bytes actually sent
00403      *
00404      * @note This function will block until all data can be sent.
00405      */
00406     u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len)
00407     {
00408         DBG("sio_write");
00409         PPPIPInterface* pIf = (PPPIPInterface*)fd;
00410         int ret;
00411         if(!pIf->m_streamAvail) { //If stream is not available (it is a shared resource) don't go further
00412             return 0;
00413         }
00414         ret = pIf->m_pStream->write(data, len, osWaitForever); //Blocks until all data is sent or an error happens
00415         if(ret != OK) {
00416             return 0;
00417         }
00418         return len;
00419     }
00420 
00421     /**
00422      * Reads from the serial device.
00423      *
00424      * @param fd serial device handle
00425      * @param data pointer to data buffer for receiving
00426      * @param len maximum length (in bytes) of data to receive
00427      * @return number of bytes actually received - may be 0 if aborted by sio_read_abort
00428      *
00429      * @note This function will block until data can be received. The blocking
00430      * can be cancelled by calling sio_read_abort().
00431      */
00432     u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len)
00433     {
00434         DBG("sio_read");
00435         PPPIPInterface* pIf = (PPPIPInterface*)fd;
00436         int ret;
00437         size_t readLen;
00438         if(!pIf->m_streamAvail) { //If stream is not available (it is a shared resource) don't go further
00439             WARN("EXIT NOT AVAIL");
00440             return 0;
00441         }
00442         ret = pIf->m_pStream->read(data, &readLen, len, osWaitForever); //Blocks until some data is received or an error happens
00443         if(ret != OK) {
00444             return 0;
00445         }
00446         DBG("ret");
00447         return readLen;
00448     }
00449 
00450     /**
00451      * Aborts a blocking sio_read() call.
00452      *
00453      * @param fd serial device handle
00454      */
00455     void sio_read_abort(sio_fd_t fd)
00456     {
00457         DBG("sio_read_abort");
00458         PPPIPInterface* pIf = (PPPIPInterface*)fd;
00459         if(!pIf->m_streamAvail) { //If stream is not available (it is a shared resource) don't go further
00460             return;
00461         }
00462         pIf->m_pStream->abortRead();
00463         DBG("ret");
00464     }
00465 
00466 }
00467