Implementation of 3G USB Modem Huawei E372

Dependents:   PYRN

Committer:
clemounet
Date:
Fri Feb 20 17:15:55 2015 +0000
Revision:
1:fbf17fb09581
Parent:
0:67daedd6f74f
Child:
2:61ac95f0af72
Add PPP networking

Who changed what in which revision?

UserRevisionLine numberNew contents of line
clemounet 0:67daedd6f74f 1
clemounet 0:67daedd6f74f 2 #include "dbg.h"
clemounet 0:67daedd6f74f 3 #include "PyrnUSBModem.h"
clemounet 0:67daedd6f74f 4 #include "HuaweiUSBModemInitializer.h"
clemounet 0:67daedd6f74f 5
clemounet 0:67daedd6f74f 6 // Command Processors
clemounet 0:67daedd6f74f 7
clemounet 0:67daedd6f74f 8 class CPINProcessor : public IATCommandsProcessor {
clemounet 0:67daedd6f74f 9 public:
clemounet 0:67daedd6f74f 10 enum PIN_STATUS { STATUS_NONE ,STATUS_SIMPIN, STATUS_SIMPUK, STATUS_READY };
clemounet 0:67daedd6f74f 11 CPINProcessor() : status(STATUS_NONE) { }
clemounet 0:67daedd6f74f 12 PIN_STATUS getStatus() { return status; }
clemounet 0:67daedd6f74f 13 private:
clemounet 0:67daedd6f74f 14 virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line) {
clemounet 0:67daedd6f74f 15 USB_DBG("GOT %s",line);
clemounet 0:67daedd6f74f 16 if(!strncmp(line, "+CPIN: READY",12)) {
clemounet 0:67daedd6f74f 17 status = STATUS_READY;
clemounet 0:67daedd6f74f 18 USB_DBG("STATUS_READY");
clemounet 0:67daedd6f74f 19 } else if(!strncmp(line, "+CPIN: SIM PIN",14)) {
clemounet 0:67daedd6f74f 20 status = STATUS_SIMPIN;
clemounet 0:67daedd6f74f 21 USB_DBG("STATUS_SIMPIN");
clemounet 0:67daedd6f74f 22 }else if(!strncmp(line, "+CPIN: SIM PUK",14)) {
clemounet 0:67daedd6f74f 23 status = STATUS_SIMPUK;
clemounet 0:67daedd6f74f 24 USB_DBG("STATUS_SIMPUK");
clemounet 0:67daedd6f74f 25 } else
clemounet 0:67daedd6f74f 26 USB_DBG("STATUS_NONE");
clemounet 0:67daedd6f74f 27 return OK;
clemounet 0:67daedd6f74f 28 }
clemounet 0:67daedd6f74f 29 virtual int onNewEntryPrompt(ATCommandsInterface* pInst) { return OK; }
clemounet 0:67daedd6f74f 30 volatile PIN_STATUS status;
clemounet 0:67daedd6f74f 31 };
clemounet 0:67daedd6f74f 32
clemounet 0:67daedd6f74f 33
clemounet 0:67daedd6f74f 34 class CREGProcessor : public IATCommandsProcessor {
clemounet 0:67daedd6f74f 35 public:
clemounet 0:67daedd6f74f 36 enum PIN_STATUS { STATUS_REGISTERING, STATUS_OK, STATUS_FAILED };
clemounet 0:67daedd6f74f 37 CREGProcessor() : status(STATUS_REGISTERING) { }
clemounet 0:67daedd6f74f 38 PIN_STATUS getStatus() { return status; }
clemounet 0:67daedd6f74f 39 private:
clemounet 0:67daedd6f74f 40 virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line) {
clemounet 0:67daedd6f74f 41 int r;
clemounet 0:67daedd6f74f 42 if( sscanf(line, "+CREG: %*d,%d", &r) == 1 ) {
clemounet 0:67daedd6f74f 43 switch(r) {
clemounet 0:67daedd6f74f 44 case 1:
clemounet 0:67daedd6f74f 45 case 5:
clemounet 0:67daedd6f74f 46 status = STATUS_OK;
clemounet 0:67daedd6f74f 47 break;
clemounet 0:67daedd6f74f 48 case 0:
clemounet 0:67daedd6f74f 49 case 2:
clemounet 0:67daedd6f74f 50 status = STATUS_REGISTERING;
clemounet 0:67daedd6f74f 51 break;
clemounet 0:67daedd6f74f 52 case 3:
clemounet 0:67daedd6f74f 53 default:
clemounet 0:67daedd6f74f 54 status = STATUS_FAILED;
clemounet 0:67daedd6f74f 55 break;
clemounet 0:67daedd6f74f 56 }
clemounet 0:67daedd6f74f 57 }
clemounet 0:67daedd6f74f 58 return OK;
clemounet 0:67daedd6f74f 59 }
clemounet 0:67daedd6f74f 60 virtual int onNewEntryPrompt(ATCommandsInterface* pInst) { return OK; }
clemounet 0:67daedd6f74f 61 volatile PIN_STATUS status;
clemounet 0:67daedd6f74f 62 };
clemounet 0:67daedd6f74f 63
clemounet 0:67daedd6f74f 64 class COPSProcessor : public IATCommandsProcessor {
clemounet 0:67daedd6f74f 65 public:
clemounet 0:67daedd6f74f 66 COPSProcessor() : valid(false) {
clemounet 0:67daedd6f74f 67 network[0] = '\0';
clemounet 0:67daedd6f74f 68 apn[0] = '\0';
clemounet 0:67daedd6f74f 69 bearer[0] = '\0';
clemounet 0:67daedd6f74f 70 }
clemounet 0:67daedd6f74f 71 char* getNetwork() { return network; }
clemounet 0:67daedd6f74f 72 char* getAPN() { return apn; }
clemounet 0:67daedd6f74f 73 char* getBearer() { return bearer; }
clemounet 0:67daedd6f74f 74 bool isValid() { return valid; }
clemounet 0:67daedd6f74f 75 private:
clemounet 0:67daedd6f74f 76 virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line) {
clemounet 0:67daedd6f74f 77 int networkId;
clemounet 0:67daedd6f74f 78 int bearerId;
clemounet 0:67daedd6f74f 79 int s = sscanf(line, "+COPS: %*d,%*d,\"%d\",%d", &networkId, &bearerId);
clemounet 0:67daedd6f74f 80 if( s == 2 ) {
clemounet 0:67daedd6f74f 81 switch(networkId) {
clemounet 0:67daedd6f74f 82 case 23415:
clemounet 0:67daedd6f74f 83 strcpy(network, "Vodafone UK");
clemounet 0:67daedd6f74f 84 strcpy(apn, "pp.vodafone.co.uk");
clemounet 0:67daedd6f74f 85 valid = true;
clemounet 0:67daedd6f74f 86 break;
clemounet 0:67daedd6f74f 87 case 20810:
clemounet 0:67daedd6f74f 88 strcpy(network, "SFR FR");
clemounet 0:67daedd6f74f 89 strcpy(apn, "websfr");
clemounet 0:67daedd6f74f 90 valid = true;
clemounet 0:67daedd6f74f 91 break;
clemounet 0:67daedd6f74f 92 default:
clemounet 0:67daedd6f74f 93 break;
clemounet 0:67daedd6f74f 94 }
clemounet 0:67daedd6f74f 95 } else
clemounet 0:67daedd6f74f 96 return OK;
clemounet 0:67daedd6f74f 97
clemounet 0:67daedd6f74f 98 switch(bearerId) {
clemounet 0:67daedd6f74f 99 case 0: strcpy(bearer, "GSM"); break;
clemounet 0:67daedd6f74f 100 case 1: strcpy(bearer, "GSM Compact"); break;
clemounet 0:67daedd6f74f 101 case 2: strcpy(bearer, "UTRAN"); break;
clemounet 0:67daedd6f74f 102 case 3: strcpy(bearer, "GSM w/EGPRS"); break;
clemounet 0:67daedd6f74f 103 case 4: strcpy(bearer, "UTRAN w/HSDPA"); break;
clemounet 0:67daedd6f74f 104 case 5: strcpy(bearer, "UTRAN w/HSUPA"); break;
clemounet 0:67daedd6f74f 105 case 6: strcpy(bearer, "UTRAN w/HSDPA and HSUPA"); break;
clemounet 0:67daedd6f74f 106 case 7: strcpy(bearer, "E-UTRAN"); break;
clemounet 0:67daedd6f74f 107 default: break;
clemounet 0:67daedd6f74f 108 }
clemounet 0:67daedd6f74f 109 return OK;
clemounet 0:67daedd6f74f 110 }
clemounet 0:67daedd6f74f 111
clemounet 0:67daedd6f74f 112 virtual int onNewEntryPrompt(ATCommandsInterface* pInst) { return OK; }
clemounet 0:67daedd6f74f 113
clemounet 0:67daedd6f74f 114 char network[24];
clemounet 0:67daedd6f74f 115 char bearer[24];
clemounet 0:67daedd6f74f 116 char apn[24];
clemounet 0:67daedd6f74f 117 volatile bool valid;
clemounet 0:67daedd6f74f 118 };
clemounet 0:67daedd6f74f 119
clemounet 0:67daedd6f74f 120 PyrnUSBModem::PyrnUSBModem(USBHost *host):
clemounet 0:67daedd6f74f 121 dongle(),
clemounet 0:67daedd6f74f 122 atStream(dongle.getSerial(3)),
clemounet 1:fbf17fb09581 123 pppStream(dongle.getSerial(3)),
clemounet 0:67daedd6f74f 124 at(&atStream),
clemounet 1:fbf17fb09581 125 ppp(&pppStream),
clemounet 1:fbf17fb09581 126 atOpen(false),
clemounet 1:fbf17fb09581 127 pppOpen(false) {
clemounet 0:67daedd6f74f 128 // If we support more dongle add the initializer here.
clemounet 0:67daedd6f74f 129 // furthermore add dongle specific initialisation int init().
clemounet 0:67daedd6f74f 130 HuaweiE372USBModemInitializer *huaweie372Initializer = new HuaweiE372USBModemInitializer(host);
clemounet 0:67daedd6f74f 131 dongle.addInitializer(huaweie372Initializer);
clemounet 0:67daedd6f74f 132 }
clemounet 0:67daedd6f74f 133
clemounet 0:67daedd6f74f 134 bool PyrnUSBModem::init() {
clemounet 0:67daedd6f74f 135
clemounet 0:67daedd6f74f 136 if(!dongle.connected()){
clemounet 0:67daedd6f74f 137 while(!dongle.connected()) {
clemounet 0:67daedd6f74f 138 USB_INFO("Dongle try connect");
clemounet 0:67daedd6f74f 139 dongle.tryConnect();
clemounet 0:67daedd6f74f 140 Thread::wait(10);
clemounet 0:67daedd6f74f 141 }
clemounet 0:67daedd6f74f 142 if(!dongle.connected())
clemounet 0:67daedd6f74f 143 return false;
clemounet 0:67daedd6f74f 144 } else
clemounet 0:67daedd6f74f 145 USB_INFO("Dongle is already connected ... continue");
clemounet 0:67daedd6f74f 146
clemounet 0:67daedd6f74f 147 if(atOpen) {
clemounet 0:67daedd6f74f 148 USB_INFO("Stream is already opened");
clemounet 0:67daedd6f74f 149 return true;
clemounet 0:67daedd6f74f 150 }
clemounet 0:67daedd6f74f 151
clemounet 0:67daedd6f74f 152 USB_INFO("Starting AT thread if needed");
clemounet 0:67daedd6f74f 153 int ret = at.open();
clemounet 0:67daedd6f74f 154 if(ret) {
clemounet 0:67daedd6f74f 155 USB_ERR("Opening AT failed");
clemounet 0:67daedd6f74f 156 return false;
clemounet 0:67daedd6f74f 157 }
clemounet 0:67daedd6f74f 158
clemounet 0:67daedd6f74f 159 USB_INFO("Sending initialisation commands");
clemounet 0:67daedd6f74f 160 ret = at.init();
clemounet 0:67daedd6f74f 161 if(ret) {
clemounet 0:67daedd6f74f 162 USB_ERR("Initialisation AT failed");
clemounet 0:67daedd6f74f 163 return false;
clemounet 0:67daedd6f74f 164 }
clemounet 0:67daedd6f74f 165
clemounet 0:67daedd6f74f 166 if(dongle.getDongleType() == WAN_DONGLE_TYPE_HUAWEI_E372) {
clemounet 0:67daedd6f74f 167 USB_INFO("Using a Vodafone E372 Dongle");
clemounet 0:67daedd6f74f 168 // Specific dongle initisation
clemounet 0:67daedd6f74f 169 ret = at.executeSimple("AT", NULL,5000);
clemounet 0:67daedd6f74f 170 if(ret != OK){
clemounet 0:67daedd6f74f 171 USB_ERR("AT Simple command ERROR");
clemounet 0:67daedd6f74f 172 return false;
clemounet 0:67daedd6f74f 173 } else {
clemounet 0:67daedd6f74f 174 USB_INFO("AT Simple command gone well!!");
clemounet 0:67daedd6f74f 175 }
clemounet 0:67daedd6f74f 176 } else {
clemounet 0:67daedd6f74f 177 USB_WARN("Using an Unknown Dongle");
clemounet 0:67daedd6f74f 178 }
clemounet 0:67daedd6f74f 179
clemounet 0:67daedd6f74f 180 ATCommandsInterface::ATResult result;
clemounet 0:67daedd6f74f 181
clemounet 0:67daedd6f74f 182 // SIM PIN Stuff here
clemounet 0:67daedd6f74f 183 bool pin = false;
clemounet 0:67daedd6f74f 184 int retries = 3;
clemounet 0:67daedd6f74f 185 do {
clemounet 0:67daedd6f74f 186 CPINProcessor cpinProcessor;
clemounet 0:67daedd6f74f 187 USB_INFO("Check CPIN STATE");
clemounet 0:67daedd6f74f 188 ret = at.execute("AT+CPIN?", &cpinProcessor, &result,5000);
clemounet 0:67daedd6f74f 189 USB_INFO("Result of command: Err code=%d\n", ret);
clemounet 0:67daedd6f74f 190 USB_INFO("ATResult: AT return=%d (code %d)\n", result.result, result.code);
clemounet 0:67daedd6f74f 191 if(ret == OK) {
clemounet 0:67daedd6f74f 192 if(cpinProcessor.getStatus() == CPINProcessor::STATUS_READY) {
clemounet 0:67daedd6f74f 193 USB_INFO("ME PIN READY\n");
clemounet 0:67daedd6f74f 194 pin = true;
clemounet 0:67daedd6f74f 195 break;
clemounet 0:67daedd6f74f 196 } else if (cpinProcessor.getStatus() == CPINProcessor::STATUS_SIMPIN) {
clemounet 0:67daedd6f74f 197 USB_INFO("ME SIM PIN NEEDED\n");
clemounet 0:67daedd6f74f 198 ret = at.executeSimple("AT+CPIN=\"0000\"", NULL,5000);
clemounet 0:67daedd6f74f 199 if(ret != OK){
clemounet 0:67daedd6f74f 200 USB_ERR("CPIN ERROR ... do not retry");
clemounet 0:67daedd6f74f 201 break;
clemounet 0:67daedd6f74f 202 } else {
clemounet 0:67daedd6f74f 203 USB_INFO("CPIN OK");
clemounet 0:67daedd6f74f 204 }
clemounet 0:67daedd6f74f 205 } else if (cpinProcessor.getStatus() == CPINProcessor::STATUS_SIMPUK) {
clemounet 0:67daedd6f74f 206 USB_INFO("CPIN IS PUKED");
clemounet 0:67daedd6f74f 207 break;
clemounet 0:67daedd6f74f 208 } else {
clemounet 0:67daedd6f74f 209 USB_ERR("UNKNOWN STATUS");
clemounet 0:67daedd6f74f 210 break;
clemounet 0:67daedd6f74f 211 }
clemounet 0:67daedd6f74f 212 } else {
clemounet 0:67daedd6f74f 213 USB_INFO("SIM PIN ERROR: SIM Probably not inserted\n");
clemounet 0:67daedd6f74f 214 break;
clemounet 0:67daedd6f74f 215 }
clemounet 0:67daedd6f74f 216 retries--;
clemounet 0:67daedd6f74f 217 } while(retries);
clemounet 0:67daedd6f74f 218
clemounet 0:67daedd6f74f 219 if(!pin) {
clemounet 0:67daedd6f74f 220 USB_ERR("Couldn't pin unlock ...");
clemounet 0:67daedd6f74f 221 return false;
clemounet 0:67daedd6f74f 222 }
clemounet 0:67daedd6f74f 223
clemounet 0:67daedd6f74f 224 //Wait for network registration
clemounet 0:67daedd6f74f 225 CREGProcessor cregProcessor;
clemounet 0:67daedd6f74f 226 do {
clemounet 0:67daedd6f74f 227 USB_INFO("Waiting for network registration");
clemounet 0:67daedd6f74f 228 ret = at.execute("AT+CREG?", &cregProcessor, &result);
clemounet 0:67daedd6f74f 229 USB_INFO("Result of command: Err code=%d\n", ret);
clemounet 0:67daedd6f74f 230 USB_INFO("ATResult: AT return=%d (code %d)\n", result.result, result.code);
clemounet 0:67daedd6f74f 231 if(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING) {
clemounet 0:67daedd6f74f 232 Thread::wait(3000);
clemounet 0:67daedd6f74f 233 }
clemounet 0:67daedd6f74f 234 } while(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING);
clemounet 0:67daedd6f74f 235 if(cregProcessor.getStatus() == CREGProcessor::STATUS_FAILED) {
clemounet 0:67daedd6f74f 236 USB_ERR("Registration denied");
clemounet 0:67daedd6f74f 237 return false;
clemounet 0:67daedd6f74f 238 }
clemounet 0:67daedd6f74f 239
clemounet 0:67daedd6f74f 240 atOpen = true;
clemounet 0:67daedd6f74f 241
clemounet 0:67daedd6f74f 242 return true;
clemounet 0:67daedd6f74f 243 }
clemounet 0:67daedd6f74f 244
clemounet 0:67daedd6f74f 245 bool PyrnUSBModem::isConnected(void) {
clemounet 0:67daedd6f74f 246 return dongle.connected();
clemounet 0:67daedd6f74f 247 }
clemounet 0:67daedd6f74f 248
clemounet 0:67daedd6f74f 249 WANDongleSerialPort *PyrnUSBModem::getAtInterface(int i) {
clemounet 0:67daedd6f74f 250 return dongle.getWANSerial(i);
clemounet 0:67daedd6f74f 251 }