Mike Pulice / ublox_C200Test

Fork of SprintUSBModemHTTPClientTest by Donatien Garnier

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SprintUSBModem.cpp Source File

SprintUSBModem.cpp

00001 /* SprintUSBModem.cpp */
00002 /* Copyright (C) 2012 mbed.org, MIT License
00003  *
00004  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
00005  * and associated documentation files (the "Software"), to deal in the Software without restriction,
00006  * including without limitation the rights to use, copy, modify, merge, publish, distribute,
00007  * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
00008  * furnished to do so, subject to the following conditions:
00009  *
00010  * The above copyright notice and this permission notice shall be included in all copies or
00011  * substantial portions of the Software.
00012  *
00013  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
00014  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00015  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
00016  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00017  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00018  */
00019 
00020 #define __DEBUG__ 4
00021 #ifndef __MODULE__
00022 #define __MODULE__ "SprintUSBModem.cpp"
00023 #endif
00024 
00025 #include "core/fwk.h"
00026 
00027 #include "SprintUSBModem.h"
00028 
00029 #define USE_ONE_PORT 1
00030 
00031 SprintUSBModem::SprintUSBModem(PinName powerGatingPin /*= NC*/, bool powerGatingOnWhenPinHigh /* = true*/, int serial /* 0 */) : m_dongle(),
00032 m_stream(m_dongle.getSerial(serial)), 
00033 m_at(&m_stream),
00034 m_sms(&m_at), m_ppp(&m_stream),
00035 m_dongleConnected(false), m_ipInit(false), m_smsInit(false), m_atOpen(false),
00036 m_powerGatingPin(powerGatingPin), m_powerGatingOnWhenPinHigh(powerGatingOnWhenPinHigh)
00037 {
00038   if( m_powerGatingPin != NC )
00039   {
00040     power(false); //Dongle will have to be powered on manually
00041   }
00042 }
00043 
00044 class CSSProcessor : public IATCommandsProcessor
00045 {
00046 public:
00047   CSSProcessor() : status(STATUS_REGISTERING)
00048   {
00049 
00050   }
00051   enum REGISTERING_STATUS { STATUS_REGISTERING, STATUS_OK };
00052   REGISTERING_STATUS getStatus()
00053   {
00054     return status;
00055   }
00056 private:
00057   virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
00058   {
00059     char b;
00060         char bc[3] = "";
00061         int sid = 99999; 
00062         
00063     //if( sscanf(line, "%*d, %c", &r) == 1 )
00064     if(sscanf(line, "%*s %c,%2s,%d", &b,bc,&sid)==3)
00065         {
00066                 if(strcmp("Z", bc) == 0)
00067                     status = STATUS_REGISTERING;
00068                 else
00069                     status = STATUS_OK;
00070     }
00071     return OK;
00072   }
00073   virtual int onNewEntryPrompt(ATCommandsInterface* pInst)
00074   {
00075     return OK;
00076   }
00077   volatile REGISTERING_STATUS status;
00078 };
00079 
00080 int SprintUSBModem::connect(const char* apn, const char* user, const char* password)
00081 {
00082   if( !m_ipInit )
00083   {
00084     m_ipInit = true;
00085     m_ppp.init();
00086   }
00087   m_ppp.setup(user, password);
00088 
00089   int ret = init();
00090   if(ret)
00091   {
00092     return ret;
00093   }
00094 
00095   #if USE_ONE_PORT
00096   m_smsInit = false; //SMS status reset
00097   //m_ussdInit = false; //USSD status reset
00098   //m_linkMonitorInit = false; //Link monitor status reset
00099   #endif
00100 
00101   ATCommandsInterface::ATResult result;
00102 
00103   if(apn != NULL)
00104   {
00105     char cmd[48];
00106     sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", apn);
00107     ret = m_at.executeSimple(cmd, &result);
00108     DBG("Result of command: Err code=%d", ret);
00109     DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
00110     DBG("APN set to %s", apn);
00111   }
00112 
00113 
00114   //Connect
00115   DBG("Connecting");
00116   #if USE_ONE_PORT
00117   m_at.close(); // Closing AT parser
00118   m_atOpen = false; //Will need to be reinitialized afterwards
00119   #endif
00120 
00121   DBG("Connecting PPP");
00122 
00123   ret = m_ppp.connect();
00124   DBG("Result of connect: Err code=%d", ret);
00125   return ret;
00126 }
00127 
00128 
00129 int SprintUSBModem::disconnect()
00130 {
00131   DBG("Disconnecting from PPP");
00132   int ret = m_ppp.disconnect();
00133   if(ret)
00134   {
00135     ERR("Disconnect returned %d, still trying to disconnect", ret);
00136   }
00137 
00138   //Ugly but leave dongle time to recover
00139   Thread::wait(500);
00140 
00141   #if USE_ONE_PORT
00142   ATCommandsInterface::ATResult result;
00143   DBG("Starting AT thread");
00144   ret = m_at.open();
00145   if(ret)
00146   {
00147     return ret;
00148   }
00149   #endif
00150 
00151   DBG("Trying to hangup");
00152 
00153   #if 0 //Does not appear to work
00154   int tries = 10;
00155   do
00156   {
00157     ret = m_at.executeSimple("+++", &result, 1000);
00158     DBG("Result of command: Err code=%d\n", ret);
00159     DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
00160   } while(tries-- && ret);
00161   if(!ret)
00162   {
00163     ret = m_at.executeSimple("ATH", &result);
00164     DBG("Result of command: Err code=%d\n", ret);
00165     DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
00166   }
00167   #endif
00168 
00169   #if USE_ONE_PORT
00170   //Reinit AT parser
00171   ret = m_at.init();
00172   DBG("Result of command: Err code=%d\n", ret);
00173   if(ret)
00174   {
00175     m_at.close(); // Closing AT parser
00176     DBG("AT Parser closed, could not complete disconnection");
00177     return NET_TIMEOUT;
00178   }
00179 
00180   #if 0
00181   m_at.close(); // Closing AT parser
00182   DBG("AT Parser closed");
00183   #endif
00184   #endif
00185   return OK;
00186 }
00187 
00188 int SprintUSBModem::sendSM(const char* number, const char* message)
00189 {
00190   int ret = init();
00191   if(ret)
00192   {
00193     return ret;
00194   }
00195 
00196   if(!m_smsInit)
00197   {
00198     ret = m_sms.init();
00199     if(ret)
00200     {
00201       return ret;
00202     }
00203     m_smsInit = true;
00204   }
00205 
00206   ret = m_sms.send(number, message);
00207   if(ret)
00208   {
00209     return ret;
00210   }
00211 
00212   return OK;
00213 }
00214 
00215 int SprintUSBModem::getSM(char* number, char* message, size_t maxLength)
00216 {
00217   int ret = init();
00218   if(ret)
00219   {
00220     return ret;
00221   }
00222 
00223   if(!m_smsInit)
00224   {
00225     ret = m_sms.init();
00226     if(ret)
00227     {
00228       return ret;
00229     }
00230     m_smsInit = true;
00231   }
00232 
00233   ret = m_sms.get(number, message, maxLength);
00234   if(ret)
00235   {
00236     return ret;
00237   }
00238 
00239   return OK;
00240 }
00241 
00242 int SprintUSBModem::getSMCount(size_t* pCount)
00243 {
00244   int ret = init();
00245   if(ret)
00246   {
00247     return ret;
00248   }
00249 
00250   if(!m_smsInit)
00251   {
00252     ret = m_sms.init();
00253     if(ret)
00254     {
00255       return ret;
00256     }
00257     m_smsInit = true;
00258   }
00259 
00260   ret = m_sms.getCount(pCount);
00261   if(ret)
00262   {
00263     return ret;
00264   }
00265 
00266   return OK;
00267 }
00268 
00269 ATCommandsInterface* SprintUSBModem::getATCommandsInterface()
00270 {
00271   return &m_at;
00272 }
00273 
00274 int SprintUSBModem::power(bool enable)
00275 {
00276   if( m_powerGatingPin == NC )
00277   {
00278     return NET_INVALID; //A pin name has not been provided in the constructor
00279   }
00280 
00281   if(!enable) //Will force components to re-init
00282   {
00283     cleanup();
00284   }
00285   
00286   DigitalOut powerGatingOut(m_powerGatingPin);
00287   powerGatingOut = m_powerGatingOnWhenPinHigh?enable:!enable;
00288 
00289   return OK;
00290 }
00291 
00292 bool SprintUSBModem::power()
00293 {
00294   if( m_powerGatingPin == NC )
00295   {
00296     return true; //Assume power is always on 
00297   }
00298   
00299   DigitalOut powerGatingOut(m_powerGatingPin);
00300   return m_powerGatingOnWhenPinHigh?powerGatingOut:!powerGatingOut;
00301 }
00302 
00303 int SprintUSBModem::init()
00304 {
00305   if( !m_dongleConnected )
00306   {
00307     if(!power())
00308     {
00309       //Obviously cannot initialize the dongle if it is disconnected...
00310       ERR("Power is off");
00311       return NET_INVALID;
00312     }
00313     m_dongleConnected = true;
00314     while( !m_dongle.connected() )
00315     {
00316       m_dongle.tryConnect();
00317       Thread::wait(100);
00318     }
00319   }
00320 
00321   if(m_atOpen)
00322   {
00323     return OK;
00324   }
00325 
00326   DBG("Starting AT thread if needed");
00327   int ret = m_at.open();
00328   if(ret)
00329   {
00330     return ret;
00331   }
00332 
00333   DBG("Sending initialisation commands");
00334   ret = m_at.init();
00335   if(ret)
00336   {
00337     return ret;
00338   }
00339 
00340   if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_SPRINT598U)
00341   {
00342     INFO("Using a Sprint 598U Dongle");
00343   }
00344   else if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_SPRINTMC5728V)
00345   {
00346     INFO("Using a Sprint MC5728V Dongle");
00347   }
00348   else if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOXC200)
00349   {
00350     INFO("Using a UBLOX C200 Dongle");
00351   }
00352   else
00353   {
00354     WARN("Using an Unknown Dongle");
00355   }
00356 
00357   ATCommandsInterface::ATResult result;
00358 
00359   //Wait for network registration
00360   CSSProcessor cssProcessor;
00361   do
00362   {
00363     DBG("Waiting for network registration");
00364     ret = m_at.execute("AT+CSS?", &cssProcessor, &result);
00365     DBG("Result of command: Err code=%d\n", ret);
00366     DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
00367     if(cssProcessor.getStatus() == CSSProcessor::STATUS_REGISTERING)
00368     {
00369       Thread::wait(3000);
00370     }
00371   } while(cssProcessor.getStatus() == CSSProcessor::STATUS_REGISTERING);
00372 
00373   m_atOpen = true;
00374 
00375   return OK;
00376 }
00377 
00378 int SprintUSBModem::cleanup()
00379 {
00380   if(m_ppp.isConnected())
00381   {
00382     WARN("Data connection is still open"); //Try to encourage good behaviour from the user
00383     m_ppp.disconnect(); 
00384   }
00385   
00386   m_smsInit = false;
00387 //  m_linkMonitorInit = false;
00388   //We don't reset m_ipInit as PPPIPInterface::init() only needs to be called once
00389   
00390   if(m_atOpen)
00391   {
00392     m_at.close();
00393     m_atOpen = false;
00394   }
00395   
00396   m_dongle.disconnect();
00397   m_dongleConnected = false;
00398   
00399   return OK;
00400 }
00401