Simple test for USSD message.

Dependencies:   CellularUSBModem

Dependents:   C027_USSDTest

Fork of UbloxUSBModem by mbed official

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers UbloxModem.cpp Source File

UbloxModem.cpp

00001 /* UbloxModem.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__ 3
00021 #ifndef __MODULE__
00022 #define __MODULE__ "UbloxModem.cpp"
00023 #endif
00024 
00025 #include "core/fwk.h"
00026 #include "sms/GSMSMSInterface.h"
00027 #include "sms/CDMASMSInterface.h"
00028 
00029 #include "UbloxModem.h"
00030 
00031 UbloxModem::UbloxModem(IOStream* atStream, IOStream* pppStream) :
00032    m_at(atStream),                          // Construct ATCommandsInterface with the AT serial channel
00033    m_CdmaSms(&m_at),                         // Construct SMSInterface with the ATCommandsInterface
00034    m_GsmSms(&m_at),                          // Construct SMSInterface with the ATCommandsInterface
00035    m_ussd(&m_at),                           // Construct USSDInterface with the ATCommandsInterface
00036    m_linkMonitor(&m_at),                    // Construct LinkMonitor with the ATCommandsInterface
00037    m_ppp(pppStream ? pppStream : atStream),    // Construct PPPIPInterface with the PPP serial channel
00038    m_ipInit(false),                         // PPIPInterface connection is initially down
00039    m_smsInit(false),                        // SMSInterface starts un-initialised
00040    m_ussdInit(false),                       // USSDInterface starts un-initialised 
00041    m_linkMonitorInit(false),                // LinkMonitor subsystem starts un-initialised
00042    m_atOpen(false),                          // ATCommandsInterface starts in a closed state
00043    m_onePort(pppStream == NULL),
00044    m_gsm(true)
00045 {
00046 }
00047 
00048 
00049 class AtiProcessor : public IATCommandsProcessor
00050 {
00051 public:
00052   AtiProcessor()
00053   { 
00054     i = 0; 
00055     str[0] = '\0'; 
00056   }
00057   const char* getInfo(void) { return str; }
00058 private:
00059   virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
00060   {
00061     int l = strlen(line);
00062     if (i + l + 2 > sizeof(str))
00063         return NET_OVERFLOW;
00064     if (i) str[i++] = ',';
00065     strcat(&str[i], line);
00066     i += l;
00067     return OK;
00068   }
00069   virtual int onNewEntryPrompt(ATCommandsInterface* pInst)
00070   {
00071     return OK;
00072   }
00073 protected:
00074   char str[256];
00075   int i;
00076 };
00077 
00078 class CREGProcessor : public IATCommandsProcessor
00079 {
00080 public:
00081   CREGProcessor(bool gsm) : status(STATUS_REGISTERING)
00082   {
00083     m_gsm = gsm;
00084   }
00085   enum REGISTERING_STATUS { STATUS_REGISTERING, STATUS_OK, STATUS_FAILED };
00086   REGISTERING_STATUS getStatus()
00087   {
00088     return status;
00089   }
00090   const char* getAtCommand()
00091   {
00092       return m_gsm ? "AT+CREG?" : "AT+CSS?";
00093   }
00094 private:
00095   virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
00096   {
00097     int r;
00098     if (m_gsm)
00099     {
00100         if( sscanf(line, "+CREG: %*d,%d", &r) == 1 )
00101         {
00102           status = (r == 1 || r == 5) ? STATUS_OK : 
00103                    (r == 0 || r == 2) ? STATUS_REGISTERING :
00104           //       (r == 3)           ? STATUS_FAILED :
00105                                         STATUS_FAILED;
00106         }
00107     }
00108     else
00109     {
00110         char bc[3] = "";
00111         if(sscanf(line, "%*s %*c,%2s,%*d",bc)==1)
00112         {
00113             status = (strcmp("Z", bc) == 0) ? STATUS_REGISTERING : STATUS_OK;
00114         }
00115     }
00116     return OK;
00117   }
00118   virtual int onNewEntryPrompt(ATCommandsInterface* pInst)
00119   {
00120     return OK;
00121   }
00122   volatile REGISTERING_STATUS status;
00123   bool m_gsm;
00124 };
00125 
00126 int UbloxModem::connect(const char* apn, const char* user, const char* password)
00127 {
00128   if( !m_ipInit )
00129   {
00130     m_ipInit = true;
00131     m_ppp.init();
00132   }
00133   m_ppp.setup(user, password, m_gsm ? DEFAULT_MSISDN_GSM : DEFAULT_MSISDN_CDMA);
00134 
00135   int ret = init();
00136   if(ret)
00137   {
00138     return ret;
00139   }
00140 
00141   if (m_onePort)
00142   {
00143      m_smsInit = false; //SMS status reset
00144      m_ussdInit = false; //USSD status reset
00145      m_linkMonitorInit = false; //Link monitor status reset
00146   }
00147 
00148   ATCommandsInterface::ATResult result;
00149 
00150   if(apn != NULL)
00151   {
00152     char cmd[48];
00153     int tries = 30;
00154     sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", apn);
00155     do //Try 30 times because for some reasons it can fail *a lot* with the K3772-Z dongle
00156     {
00157       ret = m_at.executeSimple(cmd, &result);
00158       DBG("Result of command: Err code=%d", ret);
00159       if(ret)
00160       {
00161         Thread::wait(500);
00162       }
00163     } while(ret && --tries);
00164     DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
00165     DBG("APN set to %s", apn);
00166   }
00167 
00168   //Connect
00169   DBG("Connecting");
00170   if (m_onePort)
00171   {
00172     m_at.close(); // Closing AT parser
00173     m_atOpen = false; //Will need to be reinitialized afterwards
00174   }
00175   
00176   DBG("Connecting PPP");
00177 
00178   ret = m_ppp.connect();
00179   DBG("Result of connect: Err code=%d", ret);
00180   return ret;
00181 }
00182 
00183 
00184 int UbloxModem::disconnect()
00185 {
00186   DBG("Disconnecting from PPP");
00187   int ret = m_ppp.disconnect();
00188   if(ret)
00189   {
00190     ERR("Disconnect returned %d, still trying to disconnect", ret);
00191   }
00192 
00193   //Ugly but leave dongle time to recover
00194   Thread::wait(500);
00195 
00196   if (m_onePort)
00197   {
00198     //ATCommandsInterface::ATResult result;
00199     DBG("Starting AT thread");
00200     ret = m_at.open();
00201     if(ret)
00202     {
00203       return ret;
00204     }
00205   }
00206 
00207   DBG("Trying to hangup");
00208 
00209   if (m_onePort)
00210   {
00211     //Reinit AT parser
00212     ret = m_at.init(false);
00213     DBG("Result of command: Err code=%d\n", ret);
00214     if(ret)
00215     {
00216       m_at.close(); // Closing AT parser
00217       DBG("AT Parser closed, could not complete disconnection");
00218       return NET_TIMEOUT;
00219     }
00220   
00221   }
00222   return OK;
00223 }
00224 
00225 int UbloxModem::sendSM(const char* number, const char* message)
00226 {
00227   int ret = init();
00228   if(ret)
00229   {
00230     return ret;
00231   }
00232 
00233   ISMSInterface* sms;
00234   if (m_gsm)  sms = &m_GsmSms;
00235   else        sms = &m_CdmaSms;
00236   if(!m_smsInit)
00237   {
00238     ret = sms->init();
00239     if(ret)
00240     {
00241       return ret;
00242     }
00243     m_smsInit = true;
00244   }
00245 
00246   ret = sms->send(number, message);
00247   if(ret)
00248   {
00249     return ret;
00250   }
00251 
00252   return OK;
00253 }
00254 
00255 int UbloxModem::getSM(char* number, char* message, size_t maxLength)
00256 {
00257   int ret = init();
00258   if(ret)
00259   {
00260     return ret;
00261   }
00262 
00263   ISMSInterface* sms;
00264   if (m_gsm)  sms = &m_GsmSms;
00265   else        sms = &m_CdmaSms;
00266   if(!m_smsInit)
00267   {
00268     ret = sms->init();
00269     if(ret)
00270     {
00271       return ret;
00272     }
00273     m_smsInit = true;
00274   }
00275 
00276   ret = sms->get(number, message, maxLength);
00277   if(ret)
00278   {
00279     return ret;
00280   }
00281 
00282   return OK;
00283 }
00284 
00285 int UbloxModem::getSMCount(size_t* pCount)
00286 {
00287   int ret = init();
00288   if(ret)
00289   {
00290     return ret;
00291   }
00292 
00293   ISMSInterface* sms;
00294   if (m_gsm)  sms = &m_GsmSms;
00295   else        sms = &m_CdmaSms;
00296   if(!m_smsInit)
00297   {
00298     ret = sms->init();
00299     if(ret)
00300     {
00301       return ret;
00302     }
00303     m_smsInit = true;
00304   }
00305 
00306   ret = sms->getCount(pCount);
00307   if(ret)
00308   {
00309     return ret;
00310   }
00311 
00312   return OK;
00313 }
00314 
00315 ATCommandsInterface* UbloxModem::getATCommandsInterface()
00316 {
00317   return &m_at;
00318 }
00319 
00320 int UbloxModem::init()
00321 {
00322   if(m_atOpen)
00323   {
00324     return OK;
00325   }
00326   
00327   DBG("Starting AT thread if needed");
00328   int ret = m_at.open();
00329   if(ret)
00330   {
00331     return ret;
00332   }
00333   
00334   DBG("Sending initialisation commands");
00335   ret = m_at.init(false);
00336   if(ret)
00337   {
00338     return ret;
00339   }
00340 
00341   ATCommandsInterface::ATResult result;
00342   AtiProcessor atiProcessor;
00343   do
00344   {
00345     ret = m_at.execute("ATI", &atiProcessor, &result);
00346   }
00347   while (ret != OK);
00348   {
00349     const char* info = atiProcessor.getInfo();
00350     DBG("Modem Identification [%s]", info);
00351     if (strstr(info, "LISA-C200"))
00352     {
00353         m_gsm = false;    // it is CDMA modem
00354         m_onePort = true; // force use of only one port
00355     }
00356   }
00357   
00358   CREGProcessor cregProcessor(m_gsm);
00359   //Wait for network registration
00360   do
00361   {
00362     DBG("Waiting for network registration");
00363     ret = m_at.execute(cregProcessor.getAtCommand(), &cregProcessor, &result);
00364     DBG("Result of command: Err code=%d\n", ret);
00365     DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
00366     if(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING)
00367     {
00368       Thread::wait(3000);
00369     }
00370   } while(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING);
00371   if(cregProcessor.getStatus() == CREGProcessor::STATUS_FAILED)
00372   {
00373     ERR("Registration denied");
00374     return NET_AUTH;
00375   }
00376  
00377   m_atOpen = true;
00378 
00379   return OK;
00380 }
00381 
00382 int UbloxModem::cleanup()
00383 {
00384   if(m_ppp.isConnected())
00385   {
00386     WARN("Data connection is still open"); //Try to encourage good behaviour from the user
00387     m_ppp.disconnect(); 
00388   }
00389   
00390   m_smsInit = false;
00391   m_ussdInit = false;
00392   m_linkMonitorInit = false;
00393   //We don't reset m_ipInit as PPPIPInterface::init() only needs to be called once
00394   
00395   if(m_atOpen)
00396   {
00397     m_at.close();
00398     m_atOpen = false;
00399   }
00400   
00401   return OK;
00402 }
00403 
00404 int UbloxModem::sendUSSD(const char* command, char* result, size_t maxLength)
00405 {
00406   int ret = init();
00407   if(ret)
00408   {
00409     return ret;
00410   }
00411 
00412   if(!m_ussdInit)
00413   {
00414     ret = m_ussd.init();
00415     if(ret)
00416     {
00417       return ret;
00418     }
00419     m_ussdInit = true;
00420   }
00421 
00422   ret = m_ussd.send(command, result, maxLength);
00423   if(ret)
00424   {
00425     return ret;
00426   }
00427 
00428   return OK;
00429 }
00430 
00431 int UbloxModem::getLinkState(int* pRssi, LinkMonitor::REGISTRATION_STATE* pRegistrationState, LinkMonitor::BEARER* pBearer)
00432 {
00433   int ret = init();
00434   if(ret)
00435   {
00436     return ret;
00437   }
00438   
00439   if(!m_linkMonitorInit)
00440   {
00441     ret = m_linkMonitor.init();
00442     ret = m_linkMonitor.init(m_gsm);
00443     if(ret)
00444     {
00445       return ret;
00446     }
00447     m_linkMonitorInit = true;
00448   }
00449 
00450   ret = m_linkMonitor.getState(pRssi, pRegistrationState, pBearer);
00451   if(ret)
00452   {
00453     return ret;
00454   }
00455 
00456   return OK;
00457 }
00458 
00459 #include "USBHost.h"
00460 #include "UbloxGSMModemInitializer.h"
00461 #include "UbloxCDMAModemInitializer.h"
00462 
00463 UbloxUSBModem::UbloxUSBModem() :
00464    UbloxModem(&m_atStream, &m_pppStream),
00465    m_dongle(),                              // Construct WANDongle: USB interface with two serial channels to the modem (USBSerialStream objects)
00466    m_atStream(m_dongle.getSerial(1)),       // AT commands are sent down one serial channel.
00467    m_pppStream(m_dongle.getSerial(0)),      // PPP connections are managed via another serial channel.
00468    m_dongleConnected(false)                 // Dongle is initially not ready for anything
00469 {
00470     USBHost* host = USBHost::getHostInst();
00471     m_dongle.addInitializer(new UbloxGSMModemInitializer(host));
00472     m_dongle.addInitializer(new UbloxCDMAModemInitializer(host));
00473 }
00474 
00475 int UbloxUSBModem::init()
00476 {
00477   if( !m_dongleConnected )
00478   {
00479     m_dongleConnected = true;
00480     while( !m_dongle.connected() )
00481     {
00482       m_dongle.tryConnect();
00483       Thread::wait(10);
00484     }
00485     if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAU200)
00486     {
00487       INFO("Using a u-blox LISA-U200 3G/WCDMA Modem");
00488     }
00489     else if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAC200)
00490     {
00491       INFO("Using a u-blox LISA-C200 CDMA Modem");
00492       m_gsm = false;
00493       m_onePort = true;
00494     }
00495     else
00496     {
00497       WARN("Using an Unknown Dongle");
00498     }
00499   }
00500   return UbloxModem::init();
00501 }
00502 
00503 int UbloxUSBModem::cleanup()
00504 {
00505   UbloxModem::cleanup();
00506   m_dongle.disconnect();
00507   m_dongleConnected = false;
00508   return OK;
00509 }
00510 
00511 UbloxSerModem::UbloxSerModem() :
00512    UbloxModem(&m_atStream, NULL),
00513    m_Serial(P0_15,P0_16),
00514    m_atStream(m_Serial)
00515 {
00516   m_Serial.baud(115200);
00517 }
00518