Implementation of 3G USB Modem Huawei E372

Dependents:   PYRN

Revision:
0:67daedd6f74f
Child:
1:fbf17fb09581
diff -r 000000000000 -r 67daedd6f74f PyrnUSBModem.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyrnUSBModem.cpp	Fri Feb 20 16:48:12 2015 +0000
@@ -0,0 +1,248 @@
+
+#include "dbg.h"
+#include "PyrnUSBModem.h"
+#include "HuaweiUSBModemInitializer.h"
+
+// Command Processors
+
+class CPINProcessor : public IATCommandsProcessor {
+public:
+    enum PIN_STATUS { STATUS_NONE ,STATUS_SIMPIN, STATUS_SIMPUK, STATUS_READY };
+    CPINProcessor() : status(STATUS_NONE) { }
+    PIN_STATUS getStatus() { return status; }
+private:
+    virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line) {
+        USB_DBG("GOT %s",line);
+        if(!strncmp(line, "+CPIN: READY",12)) {
+            status = STATUS_READY; 
+            USB_DBG("STATUS_READY");
+        } else if(!strncmp(line, "+CPIN: SIM PIN",14)) {
+            status = STATUS_SIMPIN;
+            USB_DBG("STATUS_SIMPIN");
+        }else if(!strncmp(line, "+CPIN: SIM PUK",14)) {
+            status = STATUS_SIMPUK;
+            USB_DBG("STATUS_SIMPUK");
+        } else
+            USB_DBG("STATUS_NONE");
+        return OK;
+    }
+    virtual int onNewEntryPrompt(ATCommandsInterface* pInst) { return OK; }
+    volatile PIN_STATUS status;
+};
+
+
+class CREGProcessor : public IATCommandsProcessor {
+public:
+    enum PIN_STATUS { STATUS_REGISTERING, STATUS_OK, STATUS_FAILED };
+    CREGProcessor() : status(STATUS_REGISTERING) { }
+    PIN_STATUS getStatus() { return status; }
+private:
+    virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line) {
+        int r;
+        if( sscanf(line, "+CREG: %*d,%d", &r) == 1 ) {
+            switch(r) {
+                case 1:
+                case 5:
+                    status = STATUS_OK;
+                    break;
+                case 0:
+                case 2:
+                    status = STATUS_REGISTERING;
+                    break;
+                case 3:
+                default:
+                    status = STATUS_FAILED;
+                    break;
+            }
+        }
+        return OK;
+    }
+    virtual int onNewEntryPrompt(ATCommandsInterface* pInst) { return OK; }
+    volatile PIN_STATUS status;
+};
+
+class COPSProcessor : public IATCommandsProcessor {
+public:
+    COPSProcessor() : valid(false) {
+        network[0] = '\0';
+        apn[0] = '\0';
+        bearer[0] = '\0';
+    }
+    char* getNetwork() { return network; }
+    char* getAPN() { return apn; }
+    char* getBearer() { return bearer; }
+    bool isValid() { return valid; }
+private:
+    virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line) {
+        int networkId;
+        int bearerId;
+        int s = sscanf(line, "+COPS: %*d,%*d,\"%d\",%d", &networkId, &bearerId);
+        if( s == 2 ) {
+            switch(networkId) {
+                case 23415:
+                    strcpy(network, "Vodafone UK");
+                    strcpy(apn, "pp.vodafone.co.uk");
+                    valid = true;
+                    break;
+                case 20810:
+                    strcpy(network, "SFR FR");
+                    strcpy(apn, "websfr");
+                    valid = true;
+                    break;
+                default:
+                    break;
+            }
+        } else
+            return OK;
+        
+        switch(bearerId) {
+            case 0: strcpy(bearer, "GSM"); break;
+            case 1: strcpy(bearer, "GSM Compact"); break;
+            case 2: strcpy(bearer, "UTRAN"); break;
+            case 3: strcpy(bearer, "GSM w/EGPRS"); break;
+            case 4: strcpy(bearer, "UTRAN w/HSDPA"); break;
+            case 5: strcpy(bearer, "UTRAN w/HSUPA"); break;
+            case 6: strcpy(bearer, "UTRAN w/HSDPA and HSUPA"); break;
+            case 7: strcpy(bearer, "E-UTRAN"); break;
+            default: break;
+        }
+        return OK;
+    }
+    
+    virtual int onNewEntryPrompt(ATCommandsInterface* pInst) { return OK; }
+    
+    char network[24];
+    char bearer[24];
+    char apn[24];
+    volatile bool valid;
+};
+
+PyrnUSBModem::PyrnUSBModem(USBHost *host): 
+        dongle(),   
+        atStream(dongle.getSerial(3)),
+        at(&atStream),
+        atOpen(false) {
+    // If we support more dongle add the initializer here.
+    // furthermore add dongle specific initialisation int init().
+    HuaweiE372USBModemInitializer *huaweie372Initializer = new HuaweiE372USBModemInitializer(host);
+    dongle.addInitializer(huaweie372Initializer);
+}
+
+bool PyrnUSBModem::init() {
+
+    if(!dongle.connected()){
+        while(!dongle.connected()) {
+          USB_INFO("Dongle try connect");
+          dongle.tryConnect();
+          Thread::wait(10);
+        }
+        if(!dongle.connected())
+            return false;
+    } else 
+        USB_INFO("Dongle is already connected ... continue");
+
+    if(atOpen) {
+        USB_INFO("Stream is already opened");
+        return true;
+    }
+
+    USB_INFO("Starting AT thread if needed");
+    int ret = at.open();
+    if(ret) {
+        USB_ERR("Opening AT failed");
+        return false;
+    }
+
+    USB_INFO("Sending initialisation commands");
+    ret = at.init();
+    if(ret) {
+        USB_ERR("Initialisation AT failed");
+        return false;
+    }
+
+    if(dongle.getDongleType() == WAN_DONGLE_TYPE_HUAWEI_E372) {
+        USB_INFO("Using a Vodafone E372 Dongle");
+        // Specific dongle initisation
+        ret = at.executeSimple("AT", NULL,5000);
+        if(ret != OK){
+            USB_ERR("AT Simple command ERROR");
+            return false;
+        } else {
+            USB_INFO("AT Simple command gone well!!");
+        }
+    } else  {
+        USB_WARN("Using an Unknown Dongle");
+    }
+
+    ATCommandsInterface::ATResult result;
+
+    // SIM PIN Stuff here
+    bool pin = false;
+    int retries = 3;
+    do {
+        CPINProcessor cpinProcessor;
+        USB_INFO("Check CPIN STATE");
+        ret = at.execute("AT+CPIN?", &cpinProcessor, &result,5000);
+        USB_INFO("Result of command: Err code=%d\n", ret);
+        USB_INFO("ATResult: AT return=%d (code %d)\n", result.result, result.code);
+        if(ret == OK) {
+            if(cpinProcessor.getStatus() == CPINProcessor::STATUS_READY) {
+                USB_INFO("ME PIN READY\n");
+                pin = true;
+                break;
+            } else if (cpinProcessor.getStatus() == CPINProcessor::STATUS_SIMPIN)  {
+                USB_INFO("ME SIM PIN NEEDED\n");
+                ret = at.executeSimple("AT+CPIN=\"0000\"", NULL,5000);
+                if(ret != OK){
+                    USB_ERR("CPIN ERROR ... do not retry");
+                    break;
+                } else {
+                    USB_INFO("CPIN OK");
+                }
+            } else if (cpinProcessor.getStatus() == CPINProcessor::STATUS_SIMPUK) {
+                USB_INFO("CPIN IS PUKED");
+                break;
+            } else {
+                USB_ERR("UNKNOWN STATUS");
+                break;
+            }
+        } else {
+            USB_INFO("SIM PIN ERROR: SIM Probably not inserted\n");
+            break;
+        }
+        retries--;
+    } while(retries);
+    
+    if(!pin) {
+        USB_ERR("Couldn't pin unlock ...");
+        return false;
+    }
+
+    //Wait for network registration
+    CREGProcessor cregProcessor;
+    do {
+        USB_INFO("Waiting for network registration");
+        ret = at.execute("AT+CREG?", &cregProcessor, &result);
+        USB_INFO("Result of command: Err code=%d\n", ret);
+        USB_INFO("ATResult: AT return=%d (code %d)\n", result.result, result.code);
+        if(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING) {
+            Thread::wait(3000);
+        }
+    } while(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING);
+    if(cregProcessor.getStatus() == CREGProcessor::STATUS_FAILED) {
+        USB_ERR("Registration denied");
+        return false;
+    }
+    
+    atOpen = true;
+
+    return true;
+}
+
+bool PyrnUSBModem::isConnected(void) {
+    return dongle.connected();
+}
+
+WANDongleSerialPort *PyrnUSBModem::getAtInterface(int i) {
+    return dongle.getWANSerial(i);
+}
\ No newline at end of file