u-blox USB modems (GSM and CDMA)

Dependencies:   CellularUSBModem

Dependents:   C027_CANInterfaceComm C027_ModemTransparentUSBCDC_revb UbloxModemHTTPClientTest C027_HTTPClientTest ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers UbloxUSBCDMAModem.cpp Source File

UbloxUSBCDMAModem.cpp

00001 /* UbloxUSBCDMAModem.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__ "UbloxUSBCDMAModem.cpp"
00023 #endif
00024 
00025 #include "core/fwk.h"
00026 
00027 #include "UbloxUSBCDMAModem.h"
00028 #include "UbloxCDMAModemInitializer.h"
00029 #include "USBHost.h"
00030 
00031 #define USE_ONE_PORT 1
00032 
00033 UbloxUSBCDMAModem::UbloxUSBCDMAModem(PinName powerGatingPin /*= NC*/, bool powerGatingOnWhenPinHigh /* = true*/, int serial /* 0 */) : m_dongle(),
00034 m_stream(m_dongle.getSerial(serial)), 
00035 m_at(&m_stream),
00036 m_sms(&m_at), m_ppp(&m_stream),
00037 m_dongleConnected(false), m_ipInit(false), m_smsInit(false), m_atOpen(false),
00038 m_powerGatingPin(powerGatingPin), m_powerGatingOnWhenPinHigh(powerGatingOnWhenPinHigh)
00039 {
00040   USBHost* host = USBHost::getHostInst();
00041   m_dongle.addInitializer(new UbloxCDMAModemInitializer(host));
00042   if( m_powerGatingPin != NC )
00043   {
00044     power(false); //Dongle will have to be powered on manually
00045   }
00046 }
00047 
00048 class CSSProcessor : public IATCommandsProcessor
00049 {
00050 public:
00051   CSSProcessor() : status(STATUS_REGISTERING)
00052   {
00053 
00054   }
00055   enum REGISTERING_STATUS { STATUS_REGISTERING, STATUS_OK };
00056   REGISTERING_STATUS getStatus()
00057   {
00058     return status;
00059   }
00060 private:
00061   virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
00062   {
00063     char b;
00064         char bc[3] = "";
00065         int sid = 99999; 
00066         
00067     //if( sscanf(line, "%*d, %c", &r) == 1 )
00068     if(sscanf(line, "%*s %c,%2s,%d", &b,bc,&sid)==3)
00069         {
00070                 if(strcmp("Z", bc) == 0)
00071                     status = STATUS_REGISTERING;
00072                 else
00073                     status = STATUS_OK;
00074     }
00075     return OK;
00076   }
00077   virtual int onNewEntryPrompt(ATCommandsInterface* pInst)
00078   {
00079     return OK;
00080   }
00081   volatile REGISTERING_STATUS status;
00082 };
00083 
00084 int UbloxUSBCDMAModem::connect(const char* apn, const char* user, const char* password)
00085 {
00086   if( !m_ipInit )
00087   {
00088     m_ipInit = true;
00089     m_ppp.init();
00090   }
00091   m_ppp.setup(user, password, DEFAULT_MSISDN_CDMA);
00092 
00093   int ret = init();
00094   if(ret)
00095   {
00096     return ret;
00097   }
00098 
00099   #if USE_ONE_PORT
00100   m_smsInit = false; //SMS status reset
00101   //m_ussdInit = false; //USSD status reset
00102   //m_linkMonitorInit = false; //Link monitor status reset
00103   #endif
00104 
00105   ATCommandsInterface::ATResult result;
00106 
00107   if(apn != NULL)
00108   {
00109     char cmd[48];
00110     sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", apn);
00111     ret = m_at.executeSimple(cmd, &result);
00112     DBG("Result of command: Err code=%d", ret);
00113     DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
00114     DBG("APN set to %s", apn);
00115   }
00116 
00117 
00118   //Connect
00119   DBG("Connecting");
00120   #if USE_ONE_PORT
00121   m_at.close(); // Closing AT parser
00122   m_atOpen = false; //Will need to be reinitialized afterwards
00123   #endif
00124 
00125   DBG("Connecting PPP");
00126 
00127   ret = m_ppp.connect();
00128   DBG("Result of connect: Err code=%d", ret);
00129   return ret;
00130 }
00131 
00132 
00133 int UbloxUSBCDMAModem::disconnect()
00134 {
00135   DBG("Disconnecting from PPP");
00136   int ret = m_ppp.disconnect();
00137   if(ret)
00138   {
00139     ERR("Disconnect returned %d, still trying to disconnect", ret);
00140   }
00141 
00142   //Ugly but leave dongle time to recover
00143   Thread::wait(500);
00144 
00145   #if USE_ONE_PORT
00146   ATCommandsInterface::ATResult result;
00147   DBG("Starting AT thread");
00148   ret = m_at.open();
00149   if(ret)
00150   {
00151     return ret;
00152   }
00153   #endif
00154 
00155   DBG("Trying to hangup");
00156 
00157   #if 0 //Does not appear to work
00158   int tries = 10;
00159   do
00160   {
00161     ret = m_at.executeSimple("+++", &result, 1000);
00162     DBG("Result of command: Err code=%d\n", ret);
00163     DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
00164   } while(tries-- && ret);
00165   if(!ret)
00166   {
00167     ret = m_at.executeSimple("ATH", &result);
00168     DBG("Result of command: Err code=%d\n", ret);
00169     DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
00170   }
00171   #endif
00172 
00173   #if USE_ONE_PORT
00174   //Reinit AT parser
00175   ret = m_at.init();
00176   DBG("Result of command: Err code=%d\n", ret);
00177   if(ret)
00178   {
00179     m_at.close(); // Closing AT parser
00180     DBG("AT Parser closed, could not complete disconnection");
00181     return NET_TIMEOUT;
00182   }
00183 
00184   #if 0
00185   m_at.close(); // Closing AT parser
00186   DBG("AT Parser closed");
00187   #endif
00188   #endif
00189   return OK;
00190 }
00191 
00192 int UbloxUSBCDMAModem::sendSM(const char* number, const char* message)
00193 {
00194   int ret = init();
00195   if(ret)
00196   {
00197     return ret;
00198   }
00199 
00200   if(!m_smsInit)
00201   {
00202     ret = m_sms.init();
00203     if(ret)
00204     {
00205       return ret;
00206     }
00207     m_smsInit = true;
00208   }
00209 
00210   ret = m_sms.send(number, message);
00211   if(ret)
00212   {
00213     return ret;
00214   }
00215 
00216   return OK;
00217 }
00218 
00219 int UbloxUSBCDMAModem::getSM(char* number, char* message, size_t maxLength)
00220 {
00221   int ret = init();
00222   if(ret)
00223   {
00224     return ret;
00225   }
00226 
00227   if(!m_smsInit)
00228   {
00229     ret = m_sms.init();
00230     if(ret)
00231     {
00232       return ret;
00233     }
00234     m_smsInit = true;
00235   }
00236 
00237   ret = m_sms.get(number, message, maxLength);
00238   if(ret)
00239   {
00240     return ret;
00241   }
00242 
00243   return OK;
00244 }
00245 
00246 int UbloxUSBCDMAModem::getSMCount(size_t* pCount)
00247 {
00248   int ret = init();
00249   if(ret)
00250   {
00251     return ret;
00252   }
00253 
00254   if(!m_smsInit)
00255   {
00256     ret = m_sms.init();
00257     if(ret)
00258     {
00259       return ret;
00260     }
00261     m_smsInit = true;
00262   }
00263 
00264   ret = m_sms.getCount(pCount);
00265   if(ret)
00266   {
00267     return ret;
00268   }
00269 
00270   return OK;
00271 }
00272 
00273 ATCommandsInterface* UbloxUSBCDMAModem::getATCommandsInterface()
00274 {
00275   return &m_at;
00276 }
00277 
00278 int UbloxUSBCDMAModem::power(bool enable)
00279 {
00280   if( m_powerGatingPin == NC )
00281   {
00282     return NET_INVALID; //A pin name has not been provided in the constructor
00283   }
00284 
00285   if(!enable) //Will force components to re-init
00286   {
00287     cleanup();
00288   }
00289   
00290   DigitalOut powerGatingOut(m_powerGatingPin);
00291   powerGatingOut = m_powerGatingOnWhenPinHigh?enable:!enable;
00292 
00293   return OK;
00294 }
00295 
00296 bool UbloxUSBCDMAModem::power()
00297 {
00298   if( m_powerGatingPin == NC )
00299   {
00300     return true; //Assume power is always on 
00301   }
00302   
00303   DigitalOut powerGatingOut(m_powerGatingPin);
00304   return m_powerGatingOnWhenPinHigh?powerGatingOut:!powerGatingOut;
00305 }
00306 
00307 int UbloxUSBCDMAModem::init()
00308 {
00309   if( !m_dongleConnected )
00310   {
00311     if(!power())
00312     {
00313       //Obviously cannot initialize the dongle if it is disconnected...
00314       ERR("Power is off");
00315       return NET_INVALID;
00316     }
00317     m_dongleConnected = true;
00318     while( !m_dongle.connected() )
00319     {
00320       m_dongle.tryConnect();
00321       Thread::wait(100);
00322     }
00323   }
00324 
00325   if(m_atOpen)
00326   {
00327     return OK;
00328   }
00329 
00330   DBG("Starting AT thread if needed");
00331   int ret = m_at.open();
00332   if(ret)
00333   {
00334     return ret;
00335   }
00336 
00337   DBG("Sending initialisation commands");
00338   ret = m_at.init();
00339   if(ret)
00340   {
00341     return ret;
00342   }
00343 
00344  if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAC200)
00345   {
00346     INFO("Using a UBLOX C200 Dongle");
00347   }
00348   else
00349   {
00350     WARN("Using an Unknown Dongle");
00351   }
00352 
00353   ATCommandsInterface::ATResult result;
00354 
00355   //Wait for network registration
00356   CSSProcessor cssProcessor;
00357   do
00358   {
00359     DBG("Waiting for network registration");
00360     ret = m_at.execute("AT+CSS?", &cssProcessor, &result);
00361     DBG("Result of command: Err code=%d\n", ret);
00362     DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
00363     if(cssProcessor.getStatus() == CSSProcessor::STATUS_REGISTERING)
00364     {
00365       Thread::wait(3000);
00366     }
00367   } while(cssProcessor.getStatus() == CSSProcessor::STATUS_REGISTERING);
00368 
00369   m_atOpen = true;
00370 
00371   return OK;
00372 }
00373 
00374 int UbloxUSBCDMAModem::cleanup()
00375 {
00376   if(m_ppp.isConnected())
00377   {
00378     WARN("Data connection is still open"); //Try to encourage good behaviour from the user
00379     m_ppp.disconnect(); 
00380   }
00381   
00382   m_smsInit = false;
00383 //  m_linkMonitorInit = false;
00384   //We don't reset m_ipInit as PPPIPInterface::init() only needs to be called once
00385   
00386   if(m_atOpen)
00387   {
00388     m_at.close();
00389     m_atOpen = false;
00390   }
00391   
00392   m_dongle.disconnect();
00393   m_dongleConnected = false;
00394   
00395   return OK;
00396 }
00397 
00398