Implementation of 3G USB Modem Huawei E372
PyrnUSBModem.cpp@0:67daedd6f74f, 2015-02-20 (annotated)
- 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?
User | Revision | Line number | New 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 | } |