GSMA version

Dependencies:   FXOS8700CQ mbed sfh7779

Fork of StarterKit by Rick McConney

Wnc.cpp

Committer:
elmkom
Date:
2017-01-09
Revision:
46:319a3f1e8ba9
Parent:
45:fe90f1fcb4e0

File content as of revision 46:319a3f1e8ba9:

#include "Wnc.h"
#include "mbed.h"
#include <cctype>
#include "config_me.h"
#include "SerialBuffered.h"


extern Serial pc;

DigitalOut  mdm_uart2_rx_boot_mode_sel(PTC17);  // on powerup, 0 = boot mode, 1 = normal boot
DigitalOut  mdm_power_on(PTB9);                 // 0 = turn modem on, 1 = turn modem off (should be held high for >5 seconds to cycle modem)
DigitalInOut  mdm_wakeup_in(PTC2);                // 0 = let modem sleep, 1 = keep modem awake -- Note: pulled high on shield

DigitalOut  mdm_reset(PTC12);                   // active high      

DigitalOut  shield_3v3_1v8_sig_trans_ena(PTC4); // 0 = disabled (all signals high impedence, 1 = translation active
DigitalOut  mdm_uart1_cts(PTD0);

DigitalOut uart1Rts(PTD1);

SerialBuffered mdm(PTD3, PTD2, 512);

int t3412Timer = 4*60*60;
int t3324Timer = 20;
bool powerSave = false;


Wnc::Wnc(void)
{
}

void Wnc::checkPassthrough()
{
    if(pc.readable())
    {
        if(pc.getc() == '~')
        passthrough();
    }
}
               

void Wnc::passthrough()
{
    pc.printf(">>\r\n");
    while(1)
    {
        char c;
        if(pc.readable())
        {
            c =  pc.getc();
            pc.putc(c);
            if(c == '~')
            {
                pc.printf("exit\r\n");
                 break;
            }
            else if(c == '<')
            {
                
                 mdm_wakeup_in = 0;
                 pc.printf("sleep\r\n");
            }
            else if(c == '>')
            {
                 mdm_wakeup_in = 1;
                 pc.printf("wake\r\n");
            }
            else if(c == '}')
            {
                 mdm_uart2_rx_boot_mode_sel = 1;
                 pc.printf("rx hi\r\n");
            }
            else if(c == '{')
            {
                 mdm_uart2_rx_boot_mode_sel = 0;
                 pc.printf("rx low\r\n");
            }

            else if(c == '^')
            {
                pc.printf("reboot\r\n");
                NVIC_SystemReset();
            }
            else
            {
               
                mdm.putc(c);
            }
        }
        if(mdm.readable())
            pc.putc(mdm.getc());
    }
}

bool Wnc::isPowerSaveOn()
{
    return powerSave;
}

void Wnc::resumePowerSave()
{
    mdm_wakeup_in = 0;
}

int Wnc::gett3412Timer()
{
    return t3412Timer;
}

int Wnc::gett3324Timer()
{
    return t3324Timer;
}

char* Wnc::read(int timeout_ms)
{
    static char response[3200]; 
    int len = 0;
    char c;
    
    if(timeout_ms > 0) // read until timeout or OK
    {
        Timer timer;
        timer.start();
        while ((len < (3200-1)) && (timer.read_ms() < timeout_ms)) {
            if (mdm.readable()) {
                c = mdm.getc();
                // replace \r\n to make debug messages more compact
                if(c == '\r') c = ' ';
                if(c == '\n') c = ' ';
                
                response[len++] = c;
                if(len>1 && response[len-2] == 'O' && response[len-1] == 'K')
                    break;

            }
        }
    }
 
    response[len] = (char)NULL;
    pc.printf("{%d %s}\r\n",len,response);
    return response;
}

char* Wnc::send(const char *cmd, int timeout_ms)
{
    char *reply;
    
    while (mdm.readable()) {
         mdm.getc();
    }
        
    int tries = 4;
    while(tries > 0)
    {
        tries--;        
        pc.printf("\r\n<%s>",cmd);
        const char *pt = cmd;
        size_t n = strlen(cmd);
        while (n--) {
            mdm.putc(*pt++);
        };
        mdm.putc('\r');
        mdm.putc('\n');
        reply = read(timeout_ms);
        if(strlen(reply) > 0 && strstr(reply,"OK") !=0)
            break; 
        checkPassthrough();
    }
    return reply;
}

bool Wnc::isModemResponding()
{    
    char *reply = send("AT",WNC_WAIT_TIME_MS);
    if(strlen(reply) > 0 && strstr(reply,"OK") !=0)
        return true;
    return false;
}

void Wnc::setIn()
{
    mdm_wakeup_in.input();
}

void Wnc::toggleWake()
{
    mdm_wakeup_in = 0;
    wait_ms(2000);  
    mdm_wakeup_in = 0; 
}

bool Wnc::init(void) {
    uart1Rts = 0;
    mdm_wakeup_in.output();
    // disable signal level translator (necessary
    // for the modem to boot properly)
    shield_3v3_1v8_sig_trans_ena = 0;

    // Hard reset the modem (doesn't go through
    // the signal level translator)
    mdm_reset = 1;
    
   // wait a moment for the modem to react
    wait_ms(10);
    
    // Let modem boot
    mdm_reset = 0;
    
    // wait a moment for the modem to react
    wait(1.0);
    
    // power modem on //off
    mdm_power_on = 0; //1;
    
    // insure modem boots into normal operating mode
    // and does not go to sleep when powered on
    mdm_uart2_rx_boot_mode_sel = 1;
    mdm_wakeup_in = 1;
    
    // initialze comm with the modem
    mdm.baud(115200);
    // clear out potential garbage
    while (mdm.readable())
      mdm.getc();

    mdm_uart1_cts = 0;
    
    // wait a moment for the modem to react to signal
    // conditions while the level translator is disabled
    // (sorry, don't have enough information to know
    // what exactly the modem is doing with the current
    // pin settings)
    wait(1.0);

    // enable the signal level translator to start
    // modem reset process (modem will be powered down)
    shield_3v3_1v8_sig_trans_ena = 1;
    
    // Give the modem 60 secons to start responding by
    // sending simple 'AT' commands to modem once per second.
    Timer timer;
    timer.start();
    while (timer.read() < 60) {
        SetLedColor(0x1); //red     
        if(isModemResponding())
        {
            SetLedColor(0);
            //mdm_uart2_rx_boot_mode_sel = 0;
            return true; 
        }
        SetLedColor(0); //off
        wait_ms(1000 - (timer.read_ms() % 1000));
        pc.printf("\r%d",timer.read_ms()/1000);
         
    }
    return false;       
}
int Wnc::secToTau(int time)
{
    /*
    0 - value is incremented in multiples of 10 minutes
    1 - value is incremented in multiples of 1 hour
    2 - value is incremented in multiples of 10 hours
    3 - value is incremented in multiples of 2 seconds
    4 - value is incremented in multiples of 30 seconds
    5 - value is incremented in multiples of 1 minute
*/
    if(time/2 < 32)
    {
        return (0x3<<5)+time/2;
    }
    else if(time/30 < 32)
    {
        return (0x4<<5)+time/30;
    }
    else if(time/60 < 32)
    {
        return (0x5<<5)+time/60;
    }
    else if(time/3600 < 32)
    {
        return (0x1<<5)+time/3600;
    }
    else if(time/36000 < 32)
    {
        return (0x2<<5)+time/36000;
    }
    else
        return (0x7<<5);
        

}
int Wnc::secToActivity(int time)
{
    /*
    0 - value is incremented in multiples of 2 seconds
    1 - value is incremented in multiples of 1 minute
    2 - value is incremented in multiples of decihours
    7 - value indicates that the timer is deactivated.
    */
    if(time/2 < 32)
    {
        return (0x0<<5)+time/2;
    }
    else if(time/60 < 32)
    {
        return (0x1<<5)+time/60;
    }
    else if(time/36000 < 32)
    {
        return (0x2<<5)+time/36000;
    }
    else
        return (0x7<<5);

}    
void Wnc::setPowerSave(bool on,int t3412,int t3324)
{
    if(on)
    {
        t3412Timer = t3412;
        t3324Timer = t3324;
        int tau = secToTau(t3412);
        int activity = secToActivity(t3324);
        mdm_wakeup_in = 0; //allow power sleep mode
        powerSave = true;
        char cmd[32];
        snprintf(cmd,sizeof(cmd),"AT+CPSMS=1,,,%d,%d",tau,activity);
        send(cmd,  WNC_WAIT_TIME_MS);
    }
    else
    {
        mdm_wakeup_in = 1; //disallow power sleep mode
        powerSave = false;
        send("AT+CPSMS=0",  WNC_WAIT_TIME_MS);
    }
}

char* Wnc::getIccid()
{
    static char iccidBuf[32];
    iccidBuf[0] = NULL;
    char* reply = send("AT%CCID",500);
    int index = 0;
    int begin = -1;
    int i = 0;

    while (reply[index]) { // While there are more characters to process...
        if (begin == -1 && isdigit(reply[index])) { // Upon finding a digit, ...
            begin = index;
        }
        if(begin != -1)
        { 
            if(isdigit(reply[index]))
            { 
                iccidBuf[i++] = reply[index];
            }
            else
            {
                iccidBuf[i++] = NULL;
                return iccidBuf;
            }
        }
        index++;
    }
    return iccidBuf;
}

void Wnc::wakeFromPowerSave()
{
    mdm_wakeup_in = 1;
    pc.printf("wake from power save\r\n");
}

bool Wnc::cmdFailed(char* reply,char* msg)
{
    if(strstr(reply,"OK") > 0)
        return false;
    pc.printf("%s\r\n",msg);
    return true;
}
    
bool Wnc::startInternet()
{
  char *reply;
  reply = send("ATE1",WNC_WAIT_TIME_MS);           // Echo ON
  char apn [32];
  snprintf(apn,sizeof(apn),"AT%%PDNSET=1,%s,IP",MY_APN_STR);

  reply = send(apn, 2*WNC_WAIT_TIME_MS); // Set APN, cmd seems to take a little longer sometimes
  if(cmdFailed(reply,"Failed to set APN")) return false;

  reply = send("AT%PDNSET?",  WNC_WAIT_TIME_MS);
  
  //pc.printf("Wiating ...\r\n");
  //wait(10);
  
  reply = send("AT@INTERNET=1",  WNC_WAIT_TIME_MS);  // Internet services enabled
  if(cmdFailed(reply,"Failed to start INTERNET"))
  {
    return false;
  }
  reply = send("AT@SOCKDIAL=1",  4*WNC_WAIT_TIME_MS);
  if(cmdFailed(reply,"SOCKDIAL Failed")) 
  {
     // passthrough();
      return false;
  }
  return true;
}

char* Wnc::ping(char* ip)
{
    char cmd[32];
    snprintf(cmd,sizeof(cmd),"AT@PINGREQ=\"%s\"",ip);
    return send(cmd,WNC_WAIT_TIME_MS);
}

bool Wnc::connect(char* ip, int port)
{
  char *reply;

    for(int i = 0;i<2;i++)
    {
       if(isModemResponding()) 
         break;
       wait(0.5);
    }
    
    if(isModemResponding())
    {
        reply = send("AT@SOCKCREAT=1", WNC_WAIT_TIME_MS);
        if(cmdFailed(reply,"Socket Create Failed")) return false;
    }
    else
    {
        pc.printf("Error Modem not responding\r\n");
        return false;
    }

    
    char cmd[64];

    snprintf(cmd,sizeof(cmd),"AT@SOCKCONN=1,\"%s\",%d",ip,port);
    reply = send(cmd,12*WNC_WAIT_TIME_MS);
    if(cmdFailed(reply,"Socket Connect Failed")) return false;
    
    for(int i = 0;i<10;i++)
    {
        reply = send("AT+CREG?",WNC_WAIT_TIME_MS);
        if(strlen(reply) > 0 && strstr(reply,"2,1") != 0)
        {
             pc.printf("Connected %s\r\n",reply);
            return true;
        }
        else
        {
            pc.printf("Unconnected %s\r\n",reply);
        }
        wait(1);
    }
    return false;
}

void Wnc::disconnect()
{
     send("AT@SOCKCLOSE=1", WNC_WAIT_TIME_MS);
}

char* Wnc::encode(int value, char* result, int base)                                                                                                          
{                                                                                                                                                        
    // check that the base if valid                                                                                                                      
    if ( base < 2 || base > 36 ) {                                                                                                                       
        *result = '\0';                                                                                                                                  
        return result;                                                                                                                                   
    }                                                                                                                                                    
 
    char* ptr = result, *ptr1 = result, tmp_char;                                                                                                        
    int tmp_value;                                                                                                                                       
 
    do {                                                                                                                                                 
        tmp_value = value;                                                                                                                               
        value /= base;                                                                                                                                   
        *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + (tmp_value - value * base)];                             
    } while ( value );                                                                                                                                   
 
    // Apply negative sign                                                                                                                               
    if ( tmp_value < 0 )                                                                                                                                 
    *ptr++ = '-';                                                                                                                                    
    *ptr-- = '\0';                                                                                                                                       
 
    while ( ptr1 < ptr ) {                                                                                                                               
    tmp_char = *ptr;                                                                                                                                 
    *ptr-- = *ptr1;                                                                                                                                  
    *ptr1++ = tmp_char;                                                                                                                              
    }                                                                                                                                                    
    return result;                                                                                                                                       
}

bool Wnc::writeSocket(const char * s)
{

  char num2str[6];
  size_t sLen = strlen(s);
  if (sLen <= 99999)
  {
    char cmd[sLen*2+32];
    int index = snprintf(cmd,sizeof(cmd),"AT@SOCKWRITE=1,%d,\"",sLen);

    while(*s != '\0')
    {
      encode((int)*s++, num2str, 16);
      // Always 2-digit ascii hex:
      if (strlen(num2str) == 1)
      {
        num2str[2] = '\0';
        num2str[1] = num2str[0];
        num2str[0] = '0';
      }
      cmd[index++] = num2str[0];
      cmd[index++] = num2str[1];
    }
    cmd[index++] =  '"';
    cmd[index] = '\0';
    char* reply = send(cmd, WNC_WAIT_TIME_MS);
    if(cmdFailed(reply,"Send Failed")) return false;
    return true;
  }
  else
  {
    pc.puts("sockwrite Err, string to long\r\n");
    return false;
  }

}

int Wnc::hex_to_int(char A)
{
    return (A > '9')? (A &~ 0x20) - 'A' + 10: (A - '0');
}

int Wnc::hex_to_ascii(char h, char l)
{  
    return hex_to_int(h) * 16 + hex_to_int(l);      
}

int Wnc::indexOf(char* str, char c)
{
    int index = 0;
    while(str[index] != 0)
    {
        if(str[index] == c)
            return index;
        index++;
    }
    return -1;
}

char* Wnc::readSocket()
{

     static char data[1000];
     int i = 0;
     char *reply;
     reply = send("AT@SOCKREAD=1,1024",1000);
     if(strlen(reply) > 0)
     {
        int pos_start = indexOf(reply,'"');
 
        if(pos_start > 0)
        {
            pos_start+=1;
            int length  = indexOf(&reply[pos_start],'"');

            if(length > 0)
            {
                char hi;
                char low;
                for(i = 0; i < length; i++){
                    if(i % 2 != 0){
                        low = reply[pos_start++];
                        data[i/2] = (char) hex_to_ascii(hi,low);
                    }else{
                        hi = reply[pos_start++];
                    }
                }
                data[length/2] = NULL;
            }
        }
    }
    data[i] = NULL;
    return data;
}

char* Wnc::resolveDn(const char* name)
{
    char cmd[64];

    snprintf(cmd,sizeof(cmd),"AT@DNSRESVDON=\"%s\"",name);
    char* reply = send(cmd,12*WNC_WAIT_TIME_MS);
    static char ipBuf[32];
    ipBuf[0] = NULL; 
    int index = 0;
    int begin = -1;
    int i = 0;

    while (reply[index]) { // While there are more characters to process...
        if (begin == -1 && isdigit(reply[index])) { // Upon finding a digit, ...
            begin = index;
        }
        if(begin != -1)
        { 
            if(isdigit(reply[index]) || reply[index] == '.')
            { 
                ipBuf[i++] = reply[index];
            }
            else
            {
                ipBuf[i++] = NULL;
                return ipBuf;
            }
        }
        index++;
    }
    return ipBuf; 
}