Library driver for the u-blox SARA-N200 NB-IoT modem

Dependents:   sara-n200-hello-mqtt-sn

sara-n2.cpp

Committer:
KeystoneElectronic
Date:
2018-08-20
Revision:
0:87f4169aba8e
Child:
2:9b9276791c59

File content as of revision 0:87f4169aba8e:

/*
 * sara_n2.cpp
 *
 *  Created on: 08 Aug 2018
 *      Author: Janus Erasmus
 */

#include "sara_n2.h"

#define INFO_TRACE(_class, _string, ...)    printf( "%8s: " _string, _class, ##__VA_ARGS__)
#define TRACE(_string, ...)    INFO_TRACE( "SARA", _string, ##__VA_ARGS__)

SARA_N2::SARA_N2(FileHandle *fh, DigitalOut *reset_pin) :
                    mCMD(fh,"\r"),
                    mReset(reset_pin),
                    mState(MODEM_UNKNOWN)
{
    mBufferFlag = 0;
    mTimer.start();
    mElapsed = mTimer.read_ms();
    *mReset = 0;

    //mCMD.debug_on(1);
    mCMD.set_timeout(500);
    mCMD.oob("+NSONMI", callback(SARA_N2::receiveData, this));
}

SARA_N2::~SARA_N2()
{
}

void SARA_N2::receiveData(SARA_N2 *_this)
{
    _this->mBufferFlag = 1;
}


const char *registartionString(int stat)
{
    switch(stat)
    {
    case 0:
        return "Not registered";
    case 1:
        return "Registered";
    case 2:
        return "Searching";
    case 3:
        return "Registration denied";
    default:
    case 4:
        return "unknown";
    case 5:
        return "Roaming";
    case 8:
        return "Emergency only";
    }
}

void SARA_N2::fsm()
{
    //Execute FSM every 1s
    int tick = mTimer.read_ms();
    if((tick - mElapsed) < 1000)
        return;

    mElapsed = tick;

    switch(mState)
    {
    case MODEM_UNKNOWN:
        TRACE("reset modem\n");
        *mReset = 0;
        wait(1);
        *mReset = 1;
        wait(1);
        mState = MODEM_NEED_SIM;
        break;
    case MODEM_NEED_SIM:
    {
        mCMD.send("AT+CGMR");
        int major, minor;
        if(!mCMD.recv("%d.%d\n", &major, &minor))
            break;

        mCMD.send("AT+UGPIOC=11,11");
        if(!mCMD.recv("OK"))
            break;

        mCMD.send("AT+CPSMS=0");
        if(!mCMD.recv("OK"))
            break;

        mCMD.send("AT+CSCON=1");
        if(!mCMD.recv("OK"))
            break;

        mCMD.send("AT+NPSMR=1");
        if(!mCMD.recv("OK"))
            break;

        TRACE("Release: %d.%d\n", major, minor);
        wait(1);

        mCMD.send("AT+CGSN=1");
        char model[32];
        model[0] = 0;
        if(!mCMD.recv("+CGSN: %32s\n", model))
            break;

        TRACE("IMEA: %s\n", model);

        mState = MODEM_SIM_PIN;
    }
    break;
    case MODEM_SIM_PIN:
    {
        char SIMID[32];
        mCMD.send("AT+CCID?");
        if(!mCMD.recv("+CCID: %32s\n", SIMID))
            break;

        TRACE("SIM: %s\n", SIMID);

//      mCMD.send("AT+CFUN=1");
//      if(!mCMD.recv("OK"))
//          break;

        mState = MODEM_SIGNAL;

    }
    break;
    case MODEM_SIGNAL:
    {
        mCMD.send("AT+CSQ");
        int power, quality;
        if(!mCMD.recv("+CSQ: %d,%d\n", &power, &quality))
            break;

        TRACE("CSQ: %d,%d\n", power, quality);

        if(power == 99)
            break;

        if(power > 9)
            mState = MODEM_REGISTERED;
    }
    break;
    case MODEM_REGISTERED:
    {
        mCMD.send("AT+CEREG?");
        int mode, status;
        if(!mCMD.recv("+CEREG: %d,%d\n", &mode, &status))
            break;

        TRACE("Reg Status: %s\n", registartionString(status));

        if((status == 1) || (status == 5))
            mState = MODEM_ATTACHING;
    }
    break;
    case MODEM_ATTACHING:
    {
        mCMD.send("AT+CGATT?");
        int att;
        if(!mCMD.recv("+CGATT: %d\n", &att))
            break;

        TRACE("GPRS ATT: %d\n", att);

        if(att == 1)
            mState = MODEM_CONNECTED;
    }
        break;
    case MODEM_CONNECTED:
        break;
    }
}

int SARA_N2::connect(char *hostname, int port)
{
    if(mState < MODEM_CONNECTED)
        return -1;

    mCMD.send("AT+NSOCR=\"DGRAM\",17,%d", port);
    int sock;
    if(!mCMD.recv("%d\n", &sock))
        return -1;

    TRACE("Socket created %d\n", sock);

//  mCMD.send("AT+CGACT=%d", sock);
//  if(mCMD.recv("OK"))
//  {
//
//      TRACE("Socket activated %d\n", sock);
//  }
    return sock;
}

bool SARA_N2::disconnect(int id)
{
    mCMD.send("AT+NSOCL=%d", id);
    if(!mCMD.recv("OK"))
        return false;

    TRACE("Socket closed %d\n", id);
    return true;
}

uint8_t util_parse_params(char *command, char **argv, int *argc, char delimiter)
{
    uint8_t count = 0;
    *argc -= 2;
    argv[count] = command;
    char *ptr = strchr(argv[count], delimiter);

    while (ptr && (count++ < *argc))
    {
        ptr[0] = 0;
        ptr++;

        argv[count] = ptr;

        ptr = strchr(argv[count], delimiter);
    }

    count++;

    *argc = count;

    return count;
}

int SARA_N2::read(int sock_id, char *host, int *port, uint8_t* buff, int len, int timeout)
{
    mCMD.process_oob();

    if(mBufferFlag <= 0)
        return -1;

    mBufferFlag = 0;

    mCMD.send("AT+NSORF=%d,%d", sock_id, len * 2);
    int sock;
    char textBuffer[256];
    if(mCMD.recv("%d,%s\n", &sock, textBuffer))
    {
        //printf("RX %d: %s\n", sock, textBuffer);
        int hex_len = -1;
        char *argv[8];
        int argc = 8;
        util_parse_params(textBuffer, argv, &argc, ',');

        if(argc > 3)
        {
            hex_len = atoi(argv[2]);
            if(hex_len > len)
                hex_len = len;

            //printf("Data %s: %s\n", argv[2], argv[3]);

            char *hex_ptr = argv[3] + 1;
            for (int k = 0; k < hex_len; ++k)
            {
                //printf("%s", hex_ptr);
                char temp[8];
                memcpy(temp, hex_ptr, 2);
                hex_ptr += 2;
                temp[2] = 0;
                buff[k] = strtol(temp, 0, 16);
            }

            len = hex_len;

            //diag_dump_buf(buff, len);
        }
    }

    return len;
}

int SARA_N2::write(int sock_id, char *host, int port, uint8_t* buff, int len, int timeout)
{
    char textBuffer[256];
    textBuffer[0] = 0;
    for (int k = 0; k < len; ++k)
    {
        char temp[8];
        sprintf(temp, "%02X", buff[k]);
        strcat(textBuffer, temp);
    }
    //mCMD.set_timeout(timeout);
    mCMD.send("AT+NSOST=%d,\"%s\",%d,%d,\"%s\"", sock_id, host, port, len, textBuffer);
    int sock, tx_len;
    if(!mCMD.recv("%d,%d\n", &sock, &tx_len))
        tx_len = -1;

    return tx_len;
}