Implementation of 3G USB Modem Huawei E372

Dependents:   PYRN

Committer:
clemounet
Date:
Tue Apr 14 13:27:07 2015 +0000
Revision:
2:61ac95f0af72
Parent:
1:fbf17fb09581
.up (working)

Who changed what in which revision?

UserRevisionLine numberNew contents of line
clemounet 0:67daedd6f74f 1
clemounet 0:67daedd6f74f 2 #include "PyrnUSBModem.h"
clemounet 2:61ac95f0af72 3
clemounet 2:61ac95f0af72 4 #define __DEBUG__ 5
clemounet 2:61ac95f0af72 5 #ifndef __MODULE__
clemounet 2:61ac95f0af72 6 #define __MODULE__ "PyrnUSBModem.cpp"
clemounet 2:61ac95f0af72 7 #endif
clemounet 2:61ac95f0af72 8 #include "MyDebug.h"
clemounet 0:67daedd6f74f 9
clemounet 0:67daedd6f74f 10 // Command Processors
clemounet 0:67daedd6f74f 11
clemounet 0:67daedd6f74f 12 class CPINProcessor : public IATCommandsProcessor {
clemounet 0:67daedd6f74f 13 public:
clemounet 0:67daedd6f74f 14 enum PIN_STATUS { STATUS_NONE ,STATUS_SIMPIN, STATUS_SIMPUK, STATUS_READY };
clemounet 0:67daedd6f74f 15 CPINProcessor() : status(STATUS_NONE) { }
clemounet 0:67daedd6f74f 16 PIN_STATUS getStatus() { return status; }
clemounet 0:67daedd6f74f 17 private:
clemounet 0:67daedd6f74f 18 virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line) {
clemounet 2:61ac95f0af72 19 DBG("GOT %s",line);
clemounet 0:67daedd6f74f 20 if(!strncmp(line, "+CPIN: READY",12)) {
clemounet 0:67daedd6f74f 21 status = STATUS_READY;
clemounet 2:61ac95f0af72 22 DBG("STATUS_READY");
clemounet 0:67daedd6f74f 23 } else if(!strncmp(line, "+CPIN: SIM PIN",14)) {
clemounet 0:67daedd6f74f 24 status = STATUS_SIMPIN;
clemounet 2:61ac95f0af72 25 DBG("STATUS_SIMPIN");
clemounet 0:67daedd6f74f 26 }else if(!strncmp(line, "+CPIN: SIM PUK",14)) {
clemounet 0:67daedd6f74f 27 status = STATUS_SIMPUK;
clemounet 2:61ac95f0af72 28 DBG("STATUS_SIMPUK");
clemounet 0:67daedd6f74f 29 } else
clemounet 2:61ac95f0af72 30 DBG("STATUS_NONE");
clemounet 0:67daedd6f74f 31 return OK;
clemounet 0:67daedd6f74f 32 }
clemounet 0:67daedd6f74f 33 virtual int onNewEntryPrompt(ATCommandsInterface* pInst) { return OK; }
clemounet 0:67daedd6f74f 34 volatile PIN_STATUS status;
clemounet 0:67daedd6f74f 35 };
clemounet 0:67daedd6f74f 36
clemounet 0:67daedd6f74f 37
clemounet 0:67daedd6f74f 38 class CREGProcessor : public IATCommandsProcessor {
clemounet 0:67daedd6f74f 39 public:
clemounet 0:67daedd6f74f 40 enum PIN_STATUS { STATUS_REGISTERING, STATUS_OK, STATUS_FAILED };
clemounet 0:67daedd6f74f 41 CREGProcessor() : status(STATUS_REGISTERING) { }
clemounet 0:67daedd6f74f 42 PIN_STATUS getStatus() { return status; }
clemounet 0:67daedd6f74f 43 private:
clemounet 0:67daedd6f74f 44 virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line) {
clemounet 0:67daedd6f74f 45 int r;
clemounet 0:67daedd6f74f 46 if( sscanf(line, "+CREG: %*d,%d", &r) == 1 ) {
clemounet 0:67daedd6f74f 47 switch(r) {
clemounet 0:67daedd6f74f 48 case 1:
clemounet 0:67daedd6f74f 49 case 5:
clemounet 0:67daedd6f74f 50 status = STATUS_OK;
clemounet 0:67daedd6f74f 51 break;
clemounet 0:67daedd6f74f 52 case 0:
clemounet 0:67daedd6f74f 53 case 2:
clemounet 0:67daedd6f74f 54 status = STATUS_REGISTERING;
clemounet 0:67daedd6f74f 55 break;
clemounet 0:67daedd6f74f 56 case 3:
clemounet 0:67daedd6f74f 57 default:
clemounet 0:67daedd6f74f 58 status = STATUS_FAILED;
clemounet 0:67daedd6f74f 59 break;
clemounet 0:67daedd6f74f 60 }
clemounet 0:67daedd6f74f 61 }
clemounet 0:67daedd6f74f 62 return OK;
clemounet 0:67daedd6f74f 63 }
clemounet 0:67daedd6f74f 64 virtual int onNewEntryPrompt(ATCommandsInterface* pInst) { return OK; }
clemounet 0:67daedd6f74f 65 volatile PIN_STATUS status;
clemounet 0:67daedd6f74f 66 };
clemounet 0:67daedd6f74f 67
clemounet 0:67daedd6f74f 68 class COPSProcessor : public IATCommandsProcessor {
clemounet 0:67daedd6f74f 69 public:
clemounet 0:67daedd6f74f 70 COPSProcessor() : valid(false) {
clemounet 0:67daedd6f74f 71 network[0] = '\0';
clemounet 0:67daedd6f74f 72 apn[0] = '\0';
clemounet 0:67daedd6f74f 73 bearer[0] = '\0';
clemounet 0:67daedd6f74f 74 }
clemounet 0:67daedd6f74f 75 char* getNetwork() { return network; }
clemounet 0:67daedd6f74f 76 char* getAPN() { return apn; }
clemounet 0:67daedd6f74f 77 char* getBearer() { return bearer; }
clemounet 0:67daedd6f74f 78 bool isValid() { return valid; }
clemounet 0:67daedd6f74f 79 private:
clemounet 0:67daedd6f74f 80 virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line) {
clemounet 0:67daedd6f74f 81 int networkId;
clemounet 0:67daedd6f74f 82 int bearerId;
clemounet 0:67daedd6f74f 83 int s = sscanf(line, "+COPS: %*d,%*d,\"%d\",%d", &networkId, &bearerId);
clemounet 0:67daedd6f74f 84 if( s == 2 ) {
clemounet 0:67daedd6f74f 85 switch(networkId) {
clemounet 0:67daedd6f74f 86 case 23415:
clemounet 0:67daedd6f74f 87 strcpy(network, "Vodafone UK");
clemounet 0:67daedd6f74f 88 strcpy(apn, "pp.vodafone.co.uk");
clemounet 0:67daedd6f74f 89 valid = true;
clemounet 0:67daedd6f74f 90 break;
clemounet 0:67daedd6f74f 91 case 20810:
clemounet 0:67daedd6f74f 92 strcpy(network, "SFR FR");
clemounet 0:67daedd6f74f 93 strcpy(apn, "websfr");
clemounet 0:67daedd6f74f 94 valid = true;
clemounet 0:67daedd6f74f 95 break;
clemounet 0:67daedd6f74f 96 default:
clemounet 0:67daedd6f74f 97 break;
clemounet 0:67daedd6f74f 98 }
clemounet 0:67daedd6f74f 99 } else
clemounet 0:67daedd6f74f 100 return OK;
clemounet 0:67daedd6f74f 101
clemounet 0:67daedd6f74f 102 switch(bearerId) {
clemounet 0:67daedd6f74f 103 case 0: strcpy(bearer, "GSM"); break;
clemounet 0:67daedd6f74f 104 case 1: strcpy(bearer, "GSM Compact"); break;
clemounet 0:67daedd6f74f 105 case 2: strcpy(bearer, "UTRAN"); break;
clemounet 0:67daedd6f74f 106 case 3: strcpy(bearer, "GSM w/EGPRS"); break;
clemounet 0:67daedd6f74f 107 case 4: strcpy(bearer, "UTRAN w/HSDPA"); break;
clemounet 0:67daedd6f74f 108 case 5: strcpy(bearer, "UTRAN w/HSUPA"); break;
clemounet 0:67daedd6f74f 109 case 6: strcpy(bearer, "UTRAN w/HSDPA and HSUPA"); break;
clemounet 0:67daedd6f74f 110 case 7: strcpy(bearer, "E-UTRAN"); break;
clemounet 0:67daedd6f74f 111 default: break;
clemounet 0:67daedd6f74f 112 }
clemounet 0:67daedd6f74f 113 return OK;
clemounet 0:67daedd6f74f 114 }
clemounet 0:67daedd6f74f 115
clemounet 0:67daedd6f74f 116 virtual int onNewEntryPrompt(ATCommandsInterface* pInst) { return OK; }
clemounet 0:67daedd6f74f 117
clemounet 0:67daedd6f74f 118 char network[24];
clemounet 0:67daedd6f74f 119 char bearer[24];
clemounet 0:67daedd6f74f 120 char apn[24];
clemounet 0:67daedd6f74f 121 volatile bool valid;
clemounet 0:67daedd6f74f 122 };
clemounet 0:67daedd6f74f 123
clemounet 2:61ac95f0af72 124 // ==================== MODEM =====================
clemounet 2:61ac95f0af72 125
clemounet 2:61ac95f0af72 126 PyrnUSBModem::PyrnUSBModem():
clemounet 2:61ac95f0af72 127 initialiser(USBHost::getHostInst()),
clemounet 0:67daedd6f74f 128 dongle(),
clemounet 0:67daedd6f74f 129 atStream(dongle.getSerial(3)),
clemounet 2:61ac95f0af72 130 pppStream(dongle.getSerial(0)),
clemounet 0:67daedd6f74f 131 at(&atStream),
clemounet 2:61ac95f0af72 132 ppp(&pppStream),
clemounet 1:fbf17fb09581 133 atOpen(false),
clemounet 2:61ac95f0af72 134 simReady(false),
clemounet 2:61ac95f0af72 135 pppOpen(false),
clemounet 2:61ac95f0af72 136 ipInit(false) {
clemounet 2:61ac95f0af72 137 DBG("Add E372 dongle initializer");
clemounet 2:61ac95f0af72 138 dongle.addInitializer(&initialiser);
clemounet 0:67daedd6f74f 139 }
clemounet 0:67daedd6f74f 140
clemounet 0:67daedd6f74f 141 bool PyrnUSBModem::init() {
clemounet 2:61ac95f0af72 142 int ret = 0;
clemounet 2:61ac95f0af72 143
clemounet 0:67daedd6f74f 144 if(!dongle.connected()){
clemounet 2:61ac95f0af72 145 bool detectConnectedModem = false;
clemounet 2:61ac95f0af72 146 for (int x=0; x<5;x++){
clemounet 2:61ac95f0af72 147 DBG("Trying to connect the dongle");
clemounet 2:61ac95f0af72 148 dongle.tryConnect();
clemounet 2:61ac95f0af72 149 if (dongle.connected()) {
clemounet 2:61ac95f0af72 150 DBG("Great the dongle is connected - I've tried %d times to connect", x);
clemounet 2:61ac95f0af72 151 detectConnectedModem = true;
clemounet 2:61ac95f0af72 152 break; // Break out of the for loop once the dongle is connected - otherwise try for a while more
clemounet 2:61ac95f0af72 153 }
clemounet 2:61ac95f0af72 154 Thread::wait(7000);
clemounet 0:67daedd6f74f 155 }
clemounet 2:61ac95f0af72 156 if (!detectConnectedModem) {
clemounet 2:61ac95f0af72 157 // OK we got this far - so give up trying and let someone know you can't see the modem
clemounet 2:61ac95f0af72 158 ERR("There is no dongle pluged into the board, or the module does not respond. Is the module/modem switched on?");
clemounet 0:67daedd6f74f 159 return false;
clemounet 2:61ac95f0af72 160 }
clemounet 2:61ac95f0af72 161 } else {
clemounet 2:61ac95f0af72 162 INFO("Dongle is already connected ... continue");
clemounet 0:67daedd6f74f 163 }
clemounet 0:67daedd6f74f 164
clemounet 2:61ac95f0af72 165 if(atOpen) {
clemounet 2:61ac95f0af72 166 INFO("Stream is already opened go to SIM Check");
clemounet 2:61ac95f0af72 167 } else {
clemounet 2:61ac95f0af72 168
clemounet 2:61ac95f0af72 169 INFO("Starting AT thread if needed");
clemounet 2:61ac95f0af72 170 ret = at.open();
clemounet 2:61ac95f0af72 171 if(ret) {
clemounet 2:61ac95f0af72 172 ERR("Opening AT failed");
clemounet 0:67daedd6f74f 173 return false;
clemounet 2:61ac95f0af72 174 }
clemounet 2:61ac95f0af72 175
clemounet 2:61ac95f0af72 176 INFO("Sending initialisation commands");
clemounet 2:61ac95f0af72 177 // Echo 1
clemounet 2:61ac95f0af72 178 // Format CRLF
clemounet 2:61ac95f0af72 179 // Unsollicited Codes disabled
clemounet 2:61ac95f0af72 180 ret = at.init("ATZ E1 V1 ^CURC=0");
clemounet 2:61ac95f0af72 181 if(ret) {
clemounet 2:61ac95f0af72 182 ERR("Initialisation AT failed");
clemounet 2:61ac95f0af72 183 return false;
clemounet 0:67daedd6f74f 184 }
clemounet 2:61ac95f0af72 185
clemounet 2:61ac95f0af72 186 if(dongle.getDongleType() == WAN_DONGLE_TYPE_HUAWEI_E372) {
clemounet 2:61ac95f0af72 187 INFO("Using a Vodafone E372 Dongle");
clemounet 2:61ac95f0af72 188 ERR("Send CMEE cmd ...");
clemounet 2:61ac95f0af72 189 ret = at.executeSimple("AT+CMEE=1",NULL,5000);
clemounet 2:61ac95f0af72 190 if(ret != OK) {
clemounet 2:61ac95f0af72 191 ERR("CMEE cmd failed");
clemounet 2:61ac95f0af72 192 return false;
clemounet 2:61ac95f0af72 193 }
clemounet 2:61ac95f0af72 194 } else {
clemounet 2:61ac95f0af72 195 WARN("Using an Unknown Dongle.. do specific init");
clemounet 2:61ac95f0af72 196 }
clemounet 2:61ac95f0af72 197
clemounet 2:61ac95f0af72 198 atOpen = true;
clemounet 0:67daedd6f74f 199 }
clemounet 0:67daedd6f74f 200
clemounet 0:67daedd6f74f 201 ATCommandsInterface::ATResult result;
clemounet 0:67daedd6f74f 202
clemounet 2:61ac95f0af72 203 if(!simReady){
clemounet 2:61ac95f0af72 204 // SIM PIN Stuff here
clemounet 2:61ac95f0af72 205 int retries = 3;
clemounet 2:61ac95f0af72 206 do {
clemounet 2:61ac95f0af72 207 CPINProcessor cpinProcessor;
clemounet 2:61ac95f0af72 208 INFO("Check CPIN STATE");
clemounet 2:61ac95f0af72 209 ret = at.execute("AT+CPIN?", &cpinProcessor, &result,5000);
clemounet 2:61ac95f0af72 210 //INFO("Result of command: Err code=%d", ret);
clemounet 2:61ac95f0af72 211 //INFO("ATResult: AT return=%d (code %d)", result.result, result.code);
clemounet 2:61ac95f0af72 212 if(result.code == 14) {
clemounet 2:61ac95f0af72 213 WARN("SIM IS Busy retry");
clemounet 2:61ac95f0af72 214 retries++;
clemounet 2:61ac95f0af72 215 Thread::wait(500);
clemounet 2:61ac95f0af72 216 } else if(ret == OK) {
clemounet 2:61ac95f0af72 217 if(cpinProcessor.getStatus() == CPINProcessor::STATUS_READY) {
clemounet 2:61ac95f0af72 218 INFO("ME PIN READY");
clemounet 2:61ac95f0af72 219 simReady = true;
clemounet 2:61ac95f0af72 220 break;
clemounet 2:61ac95f0af72 221 } else if (cpinProcessor.getStatus() == CPINProcessor::STATUS_SIMPIN) {
clemounet 2:61ac95f0af72 222 INFO("ME SIM PIN NEEDED");
clemounet 2:61ac95f0af72 223 ret = at.executeSimple("AT+CPIN=\"0000\"",NULL,5000);
clemounet 2:61ac95f0af72 224 if(ret != OK){
clemounet 2:61ac95f0af72 225 ERR("CPIN ERROR ... do not retry");
clemounet 2:61ac95f0af72 226 break;
clemounet 2:61ac95f0af72 227 } else {
clemounet 2:61ac95f0af72 228 INFO("CPIN OK");
clemounet 2:61ac95f0af72 229 }
clemounet 2:61ac95f0af72 230 } else if (cpinProcessor.getStatus() == CPINProcessor::STATUS_SIMPUK) {
clemounet 2:61ac95f0af72 231 INFO("CPIN IS PUKED");
clemounet 0:67daedd6f74f 232 break;
clemounet 0:67daedd6f74f 233 } else {
clemounet 2:61ac95f0af72 234 ERR("UNKNOWN STATUS");
clemounet 2:61ac95f0af72 235 break;
clemounet 0:67daedd6f74f 236 }
clemounet 0:67daedd6f74f 237 } else {
clemounet 2:61ac95f0af72 238 INFO("SIM PIN ERROR: SIM Probably not inserted");
clemounet 0:67daedd6f74f 239 break;
clemounet 0:67daedd6f74f 240 }
clemounet 2:61ac95f0af72 241 retries--;
clemounet 2:61ac95f0af72 242 } while(retries);
clemounet 2:61ac95f0af72 243
clemounet 2:61ac95f0af72 244 if(!simReady) {
clemounet 2:61ac95f0af72 245 ERR("Couldn't pin unlock ...");
clemounet 2:61ac95f0af72 246 return false;
clemounet 0:67daedd6f74f 247 }
clemounet 2:61ac95f0af72 248 } else {
clemounet 2:61ac95f0af72 249 INFO("SIM PIN have been unlocked somewhere!");
clemounet 2:61ac95f0af72 250 }
clemounet 0:67daedd6f74f 251
clemounet 0:67daedd6f74f 252 //Wait for network registration
clemounet 0:67daedd6f74f 253 CREGProcessor cregProcessor;
clemounet 0:67daedd6f74f 254 do {
clemounet 2:61ac95f0af72 255 INFO("Waiting for network registration");
clemounet 0:67daedd6f74f 256 ret = at.execute("AT+CREG?", &cregProcessor, &result);
clemounet 2:61ac95f0af72 257 //INFO("Result of command: Err code=%d", ret);
clemounet 2:61ac95f0af72 258 //INFO("ATResult: AT return=%d (code %d)", result.result, result.code);
clemounet 0:67daedd6f74f 259 if(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING) {
clemounet 2:61ac95f0af72 260 Thread::wait(500);
clemounet 0:67daedd6f74f 261 }
clemounet 0:67daedd6f74f 262 } while(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING);
clemounet 0:67daedd6f74f 263 if(cregProcessor.getStatus() == CREGProcessor::STATUS_FAILED) {
clemounet 2:61ac95f0af72 264 ERR("Registration denied");
clemounet 0:67daedd6f74f 265 return false;
clemounet 0:67daedd6f74f 266 }
clemounet 0:67daedd6f74f 267
clemounet 0:67daedd6f74f 268 return true;
clemounet 0:67daedd6f74f 269 }
clemounet 0:67daedd6f74f 270
clemounet 2:61ac95f0af72 271 bool PyrnUSBModem::attached(void) {
clemounet 0:67daedd6f74f 272 return dongle.connected();
clemounet 0:67daedd6f74f 273 }
clemounet 0:67daedd6f74f 274
clemounet 2:61ac95f0af72 275 bool PyrnUSBModem::pppConnected(void) {
clemounet 2:61ac95f0af72 276 return ppp.isConnected();
clemounet 2:61ac95f0af72 277 }
clemounet 2:61ac95f0af72 278
clemounet 2:61ac95f0af72 279 /*
clemounet 0:67daedd6f74f 280 WANDongleSerialPort *PyrnUSBModem::getAtInterface(int i) {
clemounet 0:67daedd6f74f 281 return dongle.getWANSerial(i);
clemounet 2:61ac95f0af72 282 }*/
clemounet 2:61ac95f0af72 283
clemounet 2:61ac95f0af72 284 int PyrnUSBModem::connect(const char* apn, const char* user, const char* password) {
clemounet 2:61ac95f0af72 285 int ret;
clemounet 2:61ac95f0af72 286
clemounet 2:61ac95f0af72 287 if(!init()) {
clemounet 2:61ac95f0af72 288 ERR("Modem could not register");
clemounet 2:61ac95f0af72 289 return -1;
clemounet 2:61ac95f0af72 290 }
clemounet 2:61ac95f0af72 291
clemounet 2:61ac95f0af72 292 ATCommandsInterface::ATResult result;
clemounet 2:61ac95f0af72 293
clemounet 2:61ac95f0af72 294 if(apn != NULL) {
clemounet 2:61ac95f0af72 295 char cmd[48];
clemounet 2:61ac95f0af72 296 int tries = 30;
clemounet 2:61ac95f0af72 297 DBG("Setting APN to %s", apn);
clemounet 2:61ac95f0af72 298 sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", apn);
clemounet 2:61ac95f0af72 299 do {//Try 30 times because for some reasons it can fail *a lot* with the K3772-Z dongle
clemounet 2:61ac95f0af72 300 ret = at.executeSimple(cmd, &result);
clemounet 2:61ac95f0af72 301 //DBG("Result of command: Err code=%d", ret);
clemounet 2:61ac95f0af72 302 if(ret)
clemounet 2:61ac95f0af72 303 Thread::wait(500);
clemounet 2:61ac95f0af72 304 } while(ret && --tries);
clemounet 2:61ac95f0af72 305 // DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
clemounet 2:61ac95f0af72 306 }
clemounet 2:61ac95f0af72 307
clemounet 2:61ac95f0af72 308 DBG("Connecting PPP");
clemounet 2:61ac95f0af72 309 ret = ppp.connect(user, password);
clemounet 2:61ac95f0af72 310 DBG("Result of connect: Err code=%d", ret);
clemounet 2:61ac95f0af72 311
clemounet 2:61ac95f0af72 312 return ret;
clemounet 2:61ac95f0af72 313 }
clemounet 2:61ac95f0af72 314
clemounet 2:61ac95f0af72 315 int PyrnUSBModem::disconnect() {
clemounet 2:61ac95f0af72 316 DBG("Disconnecting from PPP");
clemounet 2:61ac95f0af72 317 int ret = ppp.disconnect();
clemounet 2:61ac95f0af72 318 if(ret) {
clemounet 2:61ac95f0af72 319 ERR("Disconnect returned %d, still trying to disconnect", ret);
clemounet 2:61ac95f0af72 320 }
clemounet 2:61ac95f0af72 321
clemounet 2:61ac95f0af72 322 Thread::wait(500);
clemounet 2:61ac95f0af72 323
clemounet 2:61ac95f0af72 324 return OK;
clemounet 2:61ac95f0af72 325 }
clemounet 2:61ac95f0af72 326
clemounet 2:61ac95f0af72 327 char* PyrnUSBModem::getIPAddress() {
clemounet 2:61ac95f0af72 328 // return NULL;//ppp.getIPAddress();
clemounet 2:61ac95f0af72 329 return ppp.getIPAddress();
clemounet 0:67daedd6f74f 330 }