The Hiking Pal tracking device firmware. See full description on the detail page: https://www.hackster.io/bowenfeng/hiking-pal-v1-07c02d

Dependencies:   FXOS8700CQ MODSERIAL mbed

Fork of Avnet_ATT_Cellular_IOT by Avnet

cell_modem.cpp

Committer:
stefanrousseau
Date:
2016-08-01
Revision:
64:09004cd610df
Parent:
63:90d7c69993cd
Child:
68:6e311c747045

File content as of revision 64:09004cd610df:

#include "mbed.h"
#include <cctype>
#include <string>

#include "config_me.h"
#include "wnc_control.h"
#include "hardware.h"

#define MDM_DBG_OFF                             0
#define MDM_DBG_AT_CMDS                         (1 << 0)
int mdm_dbgmask = MDM_DBG_OFF;

#define WNC_WAIT_FOR_AT_CMD_MS 40

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)
DigitalOut  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);

#define TOUPPER(a) (a) //toupper(a)

const char ok_str[] = "OK";
const char error_str[] = "ERROR";

#define MDM_OK                                  0
#define MDM_ERR_TIMEOUT                         -1

#define MAX_AT_RSP_LEN                          255

ssize_t mdm_getline(char *buff, size_t size, int timeout_ms) {
    int cin = -1;
    int cin_last;
    
    if (NULL == buff || size == 0) {
        return -1;
    }

    size_t len = 0;
    Timer timer;
    timer.start();
    while ((len < (size-1)) && (timer.read_ms() < timeout_ms)) {
        if (mdm.readable()) {
            cin_last = cin;
            cin = mdm.getc();
            if (isprint(cin)) {
                buff[len++] = (char)cin;
                continue;
            } else if (('\r' == cin_last) && ('\n' == cin)) {
                break;
            }
        }
//        wait_ms(1);
    }
    buff[len] = (char)NULL;
    
    return len;
}

int mdm_sendAtCmd(const char *cmd, const char **rsp_list, int timeout_ms) {
    // Per WNC wait:
    wait_ms(WNC_WAIT_FOR_AT_CMD_MS);

    if (cmd && strlen(cmd) > 0) {
        if (mdm_dbgmask & MDM_DBG_AT_CMDS) {
            PRINTF(MAG "ATCMD: " DEF "--> " GRN "%s" DEF "\n", cmd);
        }
        mdm.puts(cmd);
        mdm.puts("\r\n");
    }

    if (rsp_list) {
        Timer   timer;
        char    rsp[MAX_AT_RSP_LEN+1];
        int     len;
        
        timer.start();
        while (timer.read_ms() < timeout_ms) {
            len = mdm_getline(rsp, sizeof(rsp), timeout_ms - timer.read_ms());
            
            if (len < 0)
                return MDM_ERR_TIMEOUT;

            if (len == 0)
                continue;
                
            if (mdm_dbgmask & MDM_DBG_AT_CMDS) {
                PRINTF(MAG "ATRSP: " DEF "<-- " CYN "%s" DEF "\n", rsp);
            }
        
            if (rsp_list) {
                int rsp_idx = 0;
                while (rsp_list[rsp_idx]) {
                    if (strcasecmp(rsp, rsp_list[rsp_idx]) == 0) {
                        return rsp_idx;
                    }
                    rsp_idx++;
                }
            }
        }
        return MDM_ERR_TIMEOUT;
    }
    return MDM_OK;
}

int mdm_init(void) {
    // Hard reset the modem (doesn't go through
    // the signal level translator)
    mdm_reset = 0;

    // disable signal level translator (necessary
    // for the modem to boot properly).  All signals
    // except mdm_reset go through the level translator
    // and have internal pull-up/down in the module. While
    // the level translator is disabled, these pins will
    // be in the correct state.  
    shield_3v3_1v8_sig_trans_ena = 0;

    // While the level translator is disabled and ouptut pins
    // are tristated, make sure the inputs are in the same state
    // as the WNC Module pins so that when the level translator is
    // enabled, there are no differences.
    mdm_uart2_rx_boot_mode_sel = 1;   // UART2_RX should be high
    mdm_power_on = 0;                 // powr_on should be low
    mdm_wakeup_in = 1;                // wake-up should be high
    mdm_uart1_cts = 0;                // indicate that it is ok to send

   // Now, wait for the WNC Module to perform its initial boot correctly
    wait(1.0);
  
    // The WNC module initializes comms at 115200 8N1 so set it up
     mdm.baud(115200);
    
    //Now, enable the level translator, the input pins should now be the
    //same as how the M14A module is driving them with internal pull ups/downs.
    //When enabled, there will be no changes in these 4 pins...
    shield_3v3_1v8_sig_trans_ena = 1;

    // Now, give the modem 60 seconds to start responding by
    // sending simple 'AT' commands to modem once per second.
    Timer timer;
    timer.start();
    while (timer.read() < 60) {
        const char * rsp_lst[] = { ok_str, error_str, NULL };
        int rc = mdm_sendAtCmd("AT", rsp_lst, 500);
        if (rc == 0)
            return true; //timer.read();
        wait_ms(1000 - (timer.read_ms() % 1000));
        PRINTF("\r%d",timer.read_ms()/1000);
    }
    return false;       
}

int mdm_sendAtCmdRsp(const char *cmd, const char **rsp_list, int timeout_ms, string * rsp, int * len) {
    static char cmd_buf[3200];  // Need enough room for the WNC sockreads (over 3000 chars)
    size_t n = strlen(cmd);

    // Per WNC wait:
    wait_ms(WNC_WAIT_FOR_AT_CMD_MS);

    if (cmd && n > 0) {
        if (mdm_dbgmask & MDM_DBG_AT_CMDS) {
            PRINTF(MAG "ATCMD: " DEF "--> " GRN "%s" DEF "\n", cmd);
        }
//        mdm.puts(cmd);
//        mdm.puts("\r\n");
        while (n--) {
            mdm.putc(*cmd++);
            wait_us(1000);
        };
        mdm.putc('\r');
        wait_us(1000);
        mdm.putc('\n');
        wait_us(1000);
    }

    if (rsp_list) {
        rsp->erase(); // Clean up from prior cmd response
        *len = 0;
        Timer   timer;
        timer.start();
        while (timer.read_ms() < timeout_ms) {
            int lenCmd = mdm_getline(cmd_buf, sizeof(cmd_buf), timeout_ms - timer.read_ms());

            if (lenCmd == 0)
                continue;

            if (lenCmd < 0)
                return MDM_ERR_TIMEOUT;
            else {
                *len += lenCmd;
                *rsp += cmd_buf;
            }

            if (mdm_dbgmask & MDM_DBG_AT_CMDS) {
                PRINTF(MAG "ATRSP: " DEF "<-- " CYN "%s" DEF "\n", cmd_buf);
            }

            int rsp_idx = 0;
            while (rsp_list[rsp_idx]) {
                if (strcasecmp(cmd_buf, rsp_list[rsp_idx]) == 0) {
                    return rsp_idx;
                }
                rsp_idx++;
            }
        }
        return MDM_ERR_TIMEOUT;
    }

    return MDM_OK;
}

void reinitialize_mdm(void)
{
    // Initialize the modem
    PRINTF(GRN "Modem RE-initializing..." DEF "\r\n");
    if (!mdm_init()) {
        PRINTF(RED "\n\rModem RE-initialization failed!" DEF "\n");
    }
    PRINTF("\r\n");
}
// These are built on the fly
string MyServerIpAddress;
string MySocketData;

//********************************************************************************************************************************************
//* Process JSON response messages
//********************************************************************************************************************************************
bool extract_JSON(char* search_field, char* found_string)
{
    char* beginquote;
    char* endquote;
    beginquote = strchr(search_field, '{'); //start of JSON
    endquote = strchr(search_field, '}'); //end of JSON
    if (beginquote)
    {
        uint16_t ifoundlen;
        if (endquote)
        {
            ifoundlen = (uint16_t) (endquote - beginquote) + 1;
            strncpy(found_string, beginquote, ifoundlen );
            found_string[ifoundlen] = 0; //null terminate
            return true;
        }
        else
        {
            endquote = strchr(search_field, '\0'); //end of string...  sometimes the end bracket is missing
            ifoundlen = (uint16_t) (endquote - beginquote) + 1;
            strncpy(found_string, beginquote, ifoundlen );
            found_string[ifoundlen] = 0; //null terminate
            return false;
        }
    }
    else
    {
        return false;
    }
} //extract_JSON

int cell_modem_init() 
{
    int i;

    pc.baud(115200);
     // Initialize the modem
    PRINTF(GRN "Modem initializing... will take up to 60 seconds" DEF "\r\n");
    do {
        i=mdm_init();
        if (!i) {
            PRINTF(RED "Modem initialization failed!" DEF "\n");
        }
    } while (!i);
    
    //Software init
    software_init_mdm();
 
    // Resolve URL to IP address to connect to
    resolve_mdm();
    // Open the socket (connect to the server)
    sockopen_mdm();
    return (0);
}

int cell_modem_Sendreceive(char* tx_string, char* rx_string) 
{
    int iStatus = 0; //error by default
    PRINTF(DEF "\r\n");
    PRINTF(BLU "Sending to modem : %s" DEF "\r\n", &tx_string[0]); 
    sockwrite_mdm(&tx_string[0]);
    if (sockread_mdm(&MySocketData, 1024, 20))
    {
        PRINTF(DEF "\r\n");
        PRINTF(YEL "Read back : %s" DEF "\r\n", &MySocketData[0]);
        char stringToCharBuf[BUF_SIZE_FOR_N_MAX_SOCKREAD*MAX_WNC_SOCKREAD_PAYLOAD+1]; // WNC can return max of 1500 (per sockread)
        if ((MySocketData.length() + 1) < sizeof(stringToCharBuf))
        {
            strcpy(stringToCharBuf, MySocketData.c_str());
            if (extract_JSON(stringToCharBuf, &rx_string[0]))
            {
                PRINTF(GRN "JSON : %s" DEF "\n", &rx_string[0]);
                iStatus = 1; //all good
            }
        }
        else
        {
            PRINTF(RED "BUFFER not big enough for sock data!" DEF "\r\n");
        }
    }
    else
    {
        PRINTF(RED "No response..." DEF "\r\n");
    }
    return iStatus;
}