PHS module APM-002 library. see: https://developer.mbed.org/users/phsfan/notebook/abitusbmodem/
Dependencies: Socket lwip-sys lwip
Fork of AbitUSBModem by
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
Generated on Wed Jul 13 2022 04:34:32 by 1.7.2