Implementation of 3G USB Modem Huawei E372

Dependents:   PYRN

Committer:
clemounet
Date:
Fri Feb 20 16:48:12 2015 +0000
Revision:
0:67daedd6f74f
Child:
1:fbf17fb09581
3G Modem driver HUAWEI E372

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 0:67daedd6f74f 123 at(&atStream),
clemounet 0:67daedd6f74f 124 atOpen(false) {
clemounet 0:67daedd6f74f 125 // If we support more dongle add the initializer here.
clemounet 0:67daedd6f74f 126 // furthermore add dongle specific initialisation int init().
clemounet 0:67daedd6f74f 127 HuaweiE372USBModemInitializer *huaweie372Initializer = new HuaweiE372USBModemInitializer(host);
clemounet 0:67daedd6f74f 128 dongle.addInitializer(huaweie372Initializer);
clemounet 0:67daedd6f74f 129 }
clemounet 0:67daedd6f74f 130
clemounet 0:67daedd6f74f 131 bool PyrnUSBModem::init() {
clemounet 0:67daedd6f74f 132
clemounet 0:67daedd6f74f 133 if(!dongle.connected()){
clemounet 0:67daedd6f74f 134 while(!dongle.connected()) {
clemounet 0:67daedd6f74f 135 USB_INFO("Dongle try connect");
clemounet 0:67daedd6f74f 136 dongle.tryConnect();
clemounet 0:67daedd6f74f 137 Thread::wait(10);
clemounet 0:67daedd6f74f 138 }
clemounet 0:67daedd6f74f 139 if(!dongle.connected())
clemounet 0:67daedd6f74f 140 return false;
clemounet 0:67daedd6f74f 141 } else
clemounet 0:67daedd6f74f 142 USB_INFO("Dongle is already connected ... continue");
clemounet 0:67daedd6f74f 143
clemounet 0:67daedd6f74f 144 if(atOpen) {
clemounet 0:67daedd6f74f 145 USB_INFO("Stream is already opened");
clemounet 0:67daedd6f74f 146 return true;
clemounet 0:67daedd6f74f 147 }
clemounet 0:67daedd6f74f 148
clemounet 0:67daedd6f74f 149 USB_INFO("Starting AT thread if needed");
clemounet 0:67daedd6f74f 150 int ret = at.open();
clemounet 0:67daedd6f74f 151 if(ret) {
clemounet 0:67daedd6f74f 152 USB_ERR("Opening AT failed");
clemounet 0:67daedd6f74f 153 return false;
clemounet 0:67daedd6f74f 154 }
clemounet 0:67daedd6f74f 155
clemounet 0:67daedd6f74f 156 USB_INFO("Sending initialisation commands");
clemounet 0:67daedd6f74f 157 ret = at.init();
clemounet 0:67daedd6f74f 158 if(ret) {
clemounet 0:67daedd6f74f 159 USB_ERR("Initialisation AT failed");
clemounet 0:67daedd6f74f 160 return false;
clemounet 0:67daedd6f74f 161 }
clemounet 0:67daedd6f74f 162
clemounet 0:67daedd6f74f 163 if(dongle.getDongleType() == WAN_DONGLE_TYPE_HUAWEI_E372) {
clemounet 0:67daedd6f74f 164 USB_INFO("Using a Vodafone E372 Dongle");
clemounet 0:67daedd6f74f 165 // Specific dongle initisation
clemounet 0:67daedd6f74f 166 ret = at.executeSimple("AT", NULL,5000);
clemounet 0:67daedd6f74f 167 if(ret != OK){
clemounet 0:67daedd6f74f 168 USB_ERR("AT Simple command ERROR");
clemounet 0:67daedd6f74f 169 return false;
clemounet 0:67daedd6f74f 170 } else {
clemounet 0:67daedd6f74f 171 USB_INFO("AT Simple command gone well!!");
clemounet 0:67daedd6f74f 172 }
clemounet 0:67daedd6f74f 173 } else {
clemounet 0:67daedd6f74f 174 USB_WARN("Using an Unknown Dongle");
clemounet 0:67daedd6f74f 175 }
clemounet 0:67daedd6f74f 176
clemounet 0:67daedd6f74f 177 ATCommandsInterface::ATResult result;
clemounet 0:67daedd6f74f 178
clemounet 0:67daedd6f74f 179 // SIM PIN Stuff here
clemounet 0:67daedd6f74f 180 bool pin = false;
clemounet 0:67daedd6f74f 181 int retries = 3;
clemounet 0:67daedd6f74f 182 do {
clemounet 0:67daedd6f74f 183 CPINProcessor cpinProcessor;
clemounet 0:67daedd6f74f 184 USB_INFO("Check CPIN STATE");
clemounet 0:67daedd6f74f 185 ret = at.execute("AT+CPIN?", &cpinProcessor, &result,5000);
clemounet 0:67daedd6f74f 186 USB_INFO("Result of command: Err code=%d\n", ret);
clemounet 0:67daedd6f74f 187 USB_INFO("ATResult: AT return=%d (code %d)\n", result.result, result.code);
clemounet 0:67daedd6f74f 188 if(ret == OK) {
clemounet 0:67daedd6f74f 189 if(cpinProcessor.getStatus() == CPINProcessor::STATUS_READY) {
clemounet 0:67daedd6f74f 190 USB_INFO("ME PIN READY\n");
clemounet 0:67daedd6f74f 191 pin = true;
clemounet 0:67daedd6f74f 192 break;
clemounet 0:67daedd6f74f 193 } else if (cpinProcessor.getStatus() == CPINProcessor::STATUS_SIMPIN) {
clemounet 0:67daedd6f74f 194 USB_INFO("ME SIM PIN NEEDED\n");
clemounet 0:67daedd6f74f 195 ret = at.executeSimple("AT+CPIN=\"0000\"", NULL,5000);
clemounet 0:67daedd6f74f 196 if(ret != OK){
clemounet 0:67daedd6f74f 197 USB_ERR("CPIN ERROR ... do not retry");
clemounet 0:67daedd6f74f 198 break;
clemounet 0:67daedd6f74f 199 } else {
clemounet 0:67daedd6f74f 200 USB_INFO("CPIN OK");
clemounet 0:67daedd6f74f 201 }
clemounet 0:67daedd6f74f 202 } else if (cpinProcessor.getStatus() == CPINProcessor::STATUS_SIMPUK) {
clemounet 0:67daedd6f74f 203 USB_INFO("CPIN IS PUKED");
clemounet 0:67daedd6f74f 204 break;
clemounet 0:67daedd6f74f 205 } else {
clemounet 0:67daedd6f74f 206 USB_ERR("UNKNOWN STATUS");
clemounet 0:67daedd6f74f 207 break;
clemounet 0:67daedd6f74f 208 }
clemounet 0:67daedd6f74f 209 } else {
clemounet 0:67daedd6f74f 210 USB_INFO("SIM PIN ERROR: SIM Probably not inserted\n");
clemounet 0:67daedd6f74f 211 break;
clemounet 0:67daedd6f74f 212 }
clemounet 0:67daedd6f74f 213 retries--;
clemounet 0:67daedd6f74f 214 } while(retries);
clemounet 0:67daedd6f74f 215
clemounet 0:67daedd6f74f 216 if(!pin) {
clemounet 0:67daedd6f74f 217 USB_ERR("Couldn't pin unlock ...");
clemounet 0:67daedd6f74f 218 return false;
clemounet 0:67daedd6f74f 219 }
clemounet 0:67daedd6f74f 220
clemounet 0:67daedd6f74f 221 //Wait for network registration
clemounet 0:67daedd6f74f 222 CREGProcessor cregProcessor;
clemounet 0:67daedd6f74f 223 do {
clemounet 0:67daedd6f74f 224 USB_INFO("Waiting for network registration");
clemounet 0:67daedd6f74f 225 ret = at.execute("AT+CREG?", &cregProcessor, &result);
clemounet 0:67daedd6f74f 226 USB_INFO("Result of command: Err code=%d\n", ret);
clemounet 0:67daedd6f74f 227 USB_INFO("ATResult: AT return=%d (code %d)\n", result.result, result.code);
clemounet 0:67daedd6f74f 228 if(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING) {
clemounet 0:67daedd6f74f 229 Thread::wait(3000);
clemounet 0:67daedd6f74f 230 }
clemounet 0:67daedd6f74f 231 } while(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING);
clemounet 0:67daedd6f74f 232 if(cregProcessor.getStatus() == CREGProcessor::STATUS_FAILED) {
clemounet 0:67daedd6f74f 233 USB_ERR("Registration denied");
clemounet 0:67daedd6f74f 234 return false;
clemounet 0:67daedd6f74f 235 }
clemounet 0:67daedd6f74f 236
clemounet 0:67daedd6f74f 237 atOpen = true;
clemounet 0:67daedd6f74f 238
clemounet 0:67daedd6f74f 239 return true;
clemounet 0:67daedd6f74f 240 }
clemounet 0:67daedd6f74f 241
clemounet 0:67daedd6f74f 242 bool PyrnUSBModem::isConnected(void) {
clemounet 0:67daedd6f74f 243 return dongle.connected();
clemounet 0:67daedd6f74f 244 }
clemounet 0:67daedd6f74f 245
clemounet 0:67daedd6f74f 246 WANDongleSerialPort *PyrnUSBModem::getAtInterface(int i) {
clemounet 0:67daedd6f74f 247 return dongle.getWANSerial(i);
clemounet 0:67daedd6f74f 248 }