Nicholas Herriot / VodafoneK3770Lib
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers VodafoneK3770.cpp Source File

VodafoneK3770.cpp

00001 /* VodafoneK3770.cpp */
00002 /*
00003 Copyright (C) 2012 ARM Limited.
00004 
00005 Permission is hereby granted, free of charge, to any person obtaining a copy of
00006 this software and associated documentation files (the "Software"), to deal in
00007 the Software without restriction, including without limitation the rights to
00008 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
00009 of the Software, and to permit persons to whom the Software is furnished to do
00010 so, subject to the following conditions:
00011 
00012 The above copyright notice and this permission notice shall be included in all
00013 copies or substantial portions of the Software.
00014 
00015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00018 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00019 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
00021 SOFTWARE.
00022 */
00023 
00024 #define __DEBUG__ 4
00025 #ifndef __MODULE__
00026 #define __MODULE__ "VodafoneK3770.cpp"
00027 #endif
00028 
00029 #include "core/fwk.h"
00030 
00031 #include "VodafoneK3770.h"
00032 
00033 VodafoneK3770::VodafoneK3770() : m_dongle(),
00034 m_stream(m_dongle), m_at(&m_stream),
00035 m_ppp(&m_stream), m_sms(&m_at),
00036 m_dongleConnected(false), m_ipInit(false), m_smsInit(false), m_atOpen(false)
00037 {
00038 
00039 }
00040 
00041 class CREGProcessor : public IATCommandsProcessor
00042 {
00043 public:
00044   CREGProcessor() : status(STATUS_REGISTERING)
00045   {
00046 
00047   }
00048   enum REGISTERING_STATUS { STATUS_REGISTERING, STATUS_OK, STATUS_FAILED };
00049   REGISTERING_STATUS getStatus()
00050   {
00051     return status;
00052   }
00053 private:
00054   virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
00055   {
00056     int r;
00057     if( sscanf(line, "+CREG: %*d,%d", &r) == 1 )
00058     {
00059       switch(r)
00060       {
00061       case 1:
00062       case 5:
00063         status = STATUS_OK;
00064         break;
00065       case 0:
00066       case 2:
00067         status = STATUS_REGISTERING;
00068         break;
00069       case 3:
00070       default:
00071         status = STATUS_FAILED;
00072         break;
00073       }
00074     }
00075     return OK;
00076   }
00077   virtual int onNewEntryPrompt(ATCommandsInterface* pInst)
00078   {
00079     return OK;
00080   }
00081   volatile REGISTERING_STATUS status;
00082 };
00083 
00084 class COPSProcessor : public IATCommandsProcessor
00085 {
00086 public:
00087   COPSProcessor() : valid(false)
00088   {
00089     network[0] = '\0';
00090     apn[0] = '\0';
00091     bearer[0] = '\0';
00092   }
00093   char* getNetwork()
00094   {
00095     return network;
00096   }
00097   char* getAPN()
00098   {
00099     return apn;
00100   }
00101   char* getBearer()
00102   {
00103     return bearer;
00104   }
00105   bool isValid()
00106   {
00107     return valid;
00108   }
00109 private:
00110   virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
00111   {
00112     int networkId;
00113     int bearerId;
00114     int s = sscanf(line, "+COPS: %*d,%*d,\"%d\",%d", &networkId, &bearerId);
00115     if( s == 2 )
00116     {
00117       switch(networkId)
00118       {
00119       case 23415:
00120         strcpy(network, "Vodafone UK");
00121         strcpy(apn, "pp.vodafone.co.uk");
00122         valid = true;
00123         break;
00124       case 20810:
00125         strcpy(network, "SFR FR");
00126         strcpy(apn, "websfr");
00127         valid = true;
00128         break;
00129       default:
00130         break;
00131       }
00132     }
00133     else
00134     {
00135       return OK;
00136     }
00137     switch(bearerId)
00138     {
00139     case 0: strcpy(bearer, "GSM"); break;
00140     case 1: strcpy(bearer, "GSM Compact"); break;
00141     case 2: strcpy(bearer, "UTRAN"); break;
00142     case 3: strcpy(bearer, "GSM w/EGPRS"); break;
00143     case 4: strcpy(bearer, "UTRAN w/HSDPA"); break;
00144     case 5: strcpy(bearer, "UTRAN w/HSUPA"); break;
00145     case 6: strcpy(bearer, "UTRAN w/HSDPA and HSUPA"); break;
00146     case 7: strcpy(bearer, "E-UTRAN"); break;
00147 
00148     default:
00149       break;
00150     }
00151     return OK;
00152   }
00153   virtual int onNewEntryPrompt(ATCommandsInterface* pInst)
00154   {
00155     return OK;
00156   }
00157   char network[24];
00158   char bearer[24];
00159   char apn[24];
00160   volatile bool valid;
00161 };
00162 
00163 
00164 int VodafoneK3770::connect(const char* apn, const char* user, const char* password)
00165 {
00166   if( !m_ipInit )
00167   {
00168     m_ipInit = true;
00169     m_ppp.init();
00170   }
00171   m_ppp.setup(user, password);
00172 
00173   int ret = init();
00174   if(ret)
00175   {
00176     return ret;
00177   }
00178 
00179   m_smsInit = false; //SMS status reset
00180 
00181   ATCommandsInterface::ATResult result;
00182 
00183 #if 0
00184   //Get network info & select corresponding APN
00185   COPSProcessor copsProcessor;
00186   DBG("Get network info & select APN from DB");
00187   ret = m_at.execute("AT+COPS=,2;+COPS?", &copsProcessor, &result); //Configure to get operator's info in numeric code & get operator's id
00188   DBG("Result of command: Err code=%d", ret);
00189   DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
00190 
00191   if(!copsProcessor.isValid())
00192   {
00193     WARN("Connected to an unknown network, try to connect with default parameters");
00194     DBG("Connected with %s", copsProcessor.getBearer());
00195   }
00196   else
00197   {
00198     DBG("Connected to %s with %s", copsProcessor.getNetwork(), copsProcessor.getBearer());
00199     char cmd[48];
00200     sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", copsProcessor.getAPN());
00201     ret = m_at.executeSimple(cmd, &result);
00202     DBG("Result of command: Err code=%d", ret);
00203     DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
00204     DBG("APN set to %s", copsProcessor.getAPN());
00205   }
00206   #else
00207   if(apn != NULL)
00208   {
00209     char cmd[48];
00210     sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", apn);
00211     ret = m_at.executeSimple(cmd, &result);
00212     DBG("Result of command: Err code=%d", ret);
00213     DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
00214     DBG("APN set to %s", apn);
00215   }
00216   #endif
00217 
00218 
00219   //Connect
00220   DBG("Connecting");
00221   ret = m_at.executeSimple("ATDT *99#", &result);
00222   DBG("Result of command: Err code=%d", ret);
00223   DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
00224   m_at.close(); // Closing AT parser
00225   m_atOpen = false; //Will need to be reinitialized afterwards
00226 
00227   DBG("AT Parser closed");
00228   if( (ret!=NET_MOREINFO) || (result.result != ATCommandsInterface::ATResult::AT_CONNECT))
00229   {
00230     ERR("Could not connect");
00231     return ret; //Could not connect
00232   }
00233   DBG("Connecting PPP");
00234 
00235   ret = m_ppp.connect();
00236   DBG("Result of connect: Err code=%d", ret);
00237   return ret;
00238 }
00239 
00240 
00241 int VodafoneK3770::disconnect()
00242 {
00243   DBG("Disconnecting from PPP");
00244   int ret = m_ppp.disconnect();
00245   if(ret)
00246   {
00247     ERR("Disconnect returned %d, still trying to disconnect", ret);
00248   }
00249 
00250   //Ugly but leave dongle time to recover
00251   Thread::wait(500);
00252 
00253   ATCommandsInterface::ATResult result;
00254   DBG("Starting AT thread");
00255   ret = m_at.open();
00256   if(ret)
00257   {
00258     return ret;
00259   }
00260 
00261   DBG("Trying to hangup");
00262 
00263 #if 0 //Does not appear to work
00264   int tries = 10;
00265   do
00266   {
00267     ret = m_at.executeSimple("+++", &result, 1000);
00268     DBG("Result of command: Err code=%d\n", ret);
00269     DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
00270   } while(tries-- && ret);
00271   if(!ret)
00272   {
00273     ret = m_at.executeSimple("ATH", &result);
00274     DBG("Result of command: Err code=%d\n", ret);
00275     DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
00276   }
00277 #endif
00278 
00279   //Reinit AT parser
00280   ret = m_at.init();
00281   DBG("Result of command: Err code=%d\n", ret);
00282   if(ret)
00283   {
00284     m_at.close(); // Closing AT parser
00285     DBG("AT Parser closed, could not complete disconnection");
00286     return NET_TIMEOUT;
00287   }
00288 
00289   m_at.close(); // Closing AT parser
00290   DBG("AT Parser closed");
00291   return OK;
00292 }
00293 
00294 int VodafoneK3770::sendSM(const char* number, const char* message)
00295 {
00296   int ret = init();
00297   if(ret)
00298   {
00299     return ret;
00300   }
00301 
00302   if(!m_smsInit)
00303   {
00304     ret = m_sms.init();
00305     if(ret)
00306     {
00307       return ret;
00308     }
00309     m_smsInit = true;
00310   }
00311 
00312   ret = m_sms.send(number, message);
00313   if(ret)
00314   {
00315     return ret;
00316   }
00317 
00318   return OK;
00319 }
00320 
00321 int VodafoneK3770::getSM(char* number, char* message, size_t maxLength)
00322 {
00323   int ret = init();
00324   if(ret)
00325   {
00326     return ret;
00327   }
00328 
00329   if(!m_smsInit)
00330   {
00331     ret = m_sms.init();
00332     if(ret)
00333     {
00334       return ret;
00335     }
00336     m_smsInit = true;
00337   }
00338 
00339   ret = m_sms.get(number, message, maxLength);
00340   if(ret)
00341   {
00342     return ret;
00343   }
00344 
00345   return OK;
00346 }
00347 
00348 int VodafoneK3770::getSMCount(size_t* pCount)
00349 {
00350   int ret = init();
00351   if(ret)
00352   {
00353     return ret;
00354   }
00355 
00356   if(!m_smsInit)
00357   {
00358     ret = m_sms.init();
00359     if(ret)
00360     {
00361       return ret;
00362     }
00363     m_smsInit = true;
00364   }
00365 
00366   ret = m_sms.getCount(pCount);
00367   if(ret)
00368   {
00369     return ret;
00370   }
00371 
00372   return OK;
00373 }
00374 
00375 
00376 int VodafoneK3770::init()
00377 {
00378   if( !m_dongleConnected )
00379   {
00380     m_dongleConnected = true;
00381     while( !m_dongle.connected() )
00382     {
00383       m_dongle.tryConnect();
00384       Thread::wait(10);
00385     }
00386   }
00387 
00388   if(m_atOpen)
00389   {
00390     return OK;
00391   }
00392 
00393   DBG("Starting AT thread if needed");
00394   int ret = m_at.open();
00395   if(ret)
00396   {
00397     return ret;
00398   }
00399 
00400   DBG("Sending initialisation commands");
00401   ret = m_at.init();
00402   if(ret)
00403   {
00404     return ret;
00405   }
00406 
00407   DBG("Configuring unsolicited result codes support properly");
00408   //Configuring port
00409   ret = m_at.executeSimple("AT^CURC=0;^PORTSEL=1", NULL); //Huawei-specific, not 3GPP-compliant
00410   if(ret != OK)
00411   {
00412     return NET_PROTOCOL;
00413   }
00414 
00415   ATCommandsInterface::ATResult result;
00416 
00417   //Wait for network registration
00418   CREGProcessor cregProcessor;
00419   do
00420   {
00421     DBG("Waiting for network registration");
00422     ret = m_at.execute("AT+CREG?", &cregProcessor, &result);
00423     DBG("Result of command: Err code=%d\n", ret);
00424     DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
00425     if(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING)
00426     {
00427       Thread::wait(3000);
00428     }
00429   } while(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING);
00430   if(cregProcessor.getStatus() == CREGProcessor::STATUS_FAILED)
00431   {
00432     ERR("Registration denied");
00433     return NET_AUTH;
00434   }
00435 
00436   m_atOpen = true;
00437 
00438   return OK;
00439 }
00440 
00441