uses pushing box to publish to google spreadsheets with a state machine instead of a while loop

Dependents:   DCS_FINAL_CODE

Fork of GSM_PUSHING_BOX_STATE_MACHINE by DCS_TEAM

GSMLibrary.cpp

Committer:
DeWayneDennis
Date:
2015-10-21
Revision:
32:424896b5adbe
Parent:
30:421aae087064
Child:
33:2ae9a4eb6433

File content as of revision 32:424896b5adbe:

//Libraries
#include "GSMLibrary.h"
//#include "gsmqueue.h"
#include <string.h>
#include "GPRSInterface.h"
#include "gsmqueue.h"
//Global defines
#define TIMEOUTLIMIT SECONDS_TIMEOUT/TIME_CONST  //Defines how many "ticks" of the GSM will constitute "timeout" of our "watchdog timer"
#define NUM_SIZE 250

//External variables
extern Serial pc;   //To print output to computer
//extern Serial gsm;  //To communicate with GSM
extern uint8_t buffer[BUFFER_LENGTH];   //DMA queue
/**************************************************
 **          GPRS                                 **
 **************************************************/
/**
 * D1 - TX pin (RX on the WiFi side)
 * D0 - RX pin (TX on the WiFi side)
 * 19200 - Baud rate
 * "apn" - APN name
 * "username" - APN username
 * "password" - APN passowrd
 */
GPRSInterface eth(D1,D0, 19200, "ndo","","");

//Internal variables
gsm_states gsm_current_state = GSM_INITIALIZE;
int timeout_count = 0;
char state_chars[] = "iSJICS";  //For debugging - 1 char to represent each state: init, ok, signalstrength, network, turn off notifications, messagemode, read, phone, writesms, del
char* serverIP;
TCPSocketConnection sock;

//Extras for transmitter
char gsm_msg[250]; //String storing SMS message that will be sent (add 250 length to give leeway)
char gsm_header[250]; //for the http header information
char num[NUM_SIZE];   //Temporary string storage to help with concatenation of strings
char send = false;  //if true => we will send something (only if send_enable is true)
char send_enable = false;   //Sending start and stop commands to GSM via SMS changes this variable. If true, we will send SMS messages of our data received


//"Tick" of the GSM (i.e. this is a state machine)
void gsm_tick()
{
    //Don't do anything, unless i) we received a response from the GSM, ii) the watchdog timer timed out, or iii) or we are initializing the GSM
    if (queueHasResponse() || gsm_timeOut() || gsm_current_state == GSM_INITIALIZE)
    {
        //gsm_printState();   //&debug
        //printQueue();   //&debug
        gsm_nextStateLogic();   //Next state
        //gsm_mealyOutputs(); //Mealy outputs. This state machine is a little different because Mealy outputs come after the next state logic
    }
}

//Prints the current state. To save time printing, simply prints 1 character to indicate the current state.
void gsm_printState()
{
    pc.printf("S:%c;", state_chars[gsm_current_state]);
}
 
//Advance timeout counter; if timeout, return true
bool gsm_timeOut()
{
    if(++timeout_count >= TIMEOUTLIMIT){
        timeout_count = 0; 
        gsm_reset();
        return true;
    }
    else
        return false;     
}

//Have the GSM send data - L = long, S = short, hh/mm/ss for time, "lat ns" for latitute, "lon we" for longitude
void gsm_send_data(float L, float Lref, int hh, int mm, int ss, float lat, char ns, float lon, char we)
{
    //Concatenate data
    gsm_msg[0] = NULL;
    gsm_header[0] = NULL;
    int contentLength = 0;
    snprintf(num, NUM_SIZE, "&phone=%s", "3852368101");
    contentLength += strlen(num);
    strcat(gsm_msg, num);
    snprintf(num, NUM_SIZE, "&data=%f", L);
    contentLength += strlen(num);
    strcat(gsm_msg, num);
    snprintf(num, NUM_SIZE, "&dataRef=%f", Lref);
    contentLength += strlen(num);
    strcat(gsm_msg, num);
    snprintf(num, NUM_SIZE, "&dataRatio=%f", (Lref ? (L/Lref) : 0));
    contentLength += strlen(num);
    strcat(gsm_msg, num);
    snprintf(num, NUM_SIZE, "&time=%02d:%02d:%02d", hh, mm, ss);   //If there is no data from GPS, the time will just be "00:00:00" (that is okay)
    contentLength += strlen(num);
    strcat(gsm_msg, num);
    if (ns != NULL) //If there is a gps fix (i.e. the gps has data on our location), ns will be set
    { 
        snprintf(num, NUM_SIZE, "&latitude=%.4f&longitude=%.4f", (ns == 'N') ? lat : -lat, (we == 'E') ? lon : -lon);   //Use + or - rather than N/S, E/W
        contentLength += strlen(num);
        strcat(gsm_msg, num);
    }
    else {
        snprintf(num, NUM_SIZE,"&latitude=0&longitude=0");
        strcat(gsm_msg, num);    //Otherwise just send 0's for latitude and longitude
        contentLength += strlen(num);
    }

    
    //header information    
    snprintf(num, NUM_SIZE, "%s", "POST /pushingbox?devid=v941C443DE0C7B14");
    strcat(gsm_header, num);
    strcat(gsm_header, gsm_msg);
    snprintf(num, NUM_SIZE, "%s"," HTTP/1.1\r\n");
    strcat(gsm_header, num);
    snprintf(num, NUM_SIZE, "%s","Host: api.pushingbox.com\r\n");
    strcat(gsm_header, num);
    snprintf(num, NUM_SIZE, "%s","Connection: close\r\n");
    strcat(gsm_header, num);
    snprintf(num, NUM_SIZE, "%s","User-Agent: FRDM-KD64\r\n");
    strcat(gsm_header, num);
    //must have two blank lines after so the server knows that this is the end of headers
    snprintf(num, NUM_SIZE, "Content-Length: %d\r\n\r\n", contentLength);
    strcat(gsm_header, num);
    send = true;    //Mark that we are currently sending a message
}
 
//Return true if gsm is ready to send via tcp
//This only occurs if gsm received start sequence and responded appropriately
bool gsm_ready()
{
    return ((!send) && send_enable) ? true : false;
}
 
//Reset the gsm. Currently this only resets the state, whether we are currently sending a message, and whether there are messages to delete.
//It does not reset send_enable
void gsm_reset()
{
    gsm_current_state = GSM_INITIALIZE;
    send = false;
}
 
//Next state logic -----------------------------------------------------
//Note how each state (except init) checks the response received to make sure
//GSM has properly executed the command. If the response is correct, it changes
//the state so that the next command will be sent in the gsm_mealyOutputs function
//below.
void gsm_nextStateLogic()
{
    switch(gsm_current_state)
    {
        case GSM_INITIALIZE:
            timeout_count = 0;  //No AT commands have been sent: this will send the first one
            printf(">>>INIT\r\n");
            if (eth.init() != NULL) {
                printf(">>> Could not initialise. Halting!\n");
                exit(0);
            }
            gsm_current_state = GSM_CHECK_SIM;
            break;
        case GSM_CHECK_SIM:
            printf(">>>CHECK SIM\r\n");
            if (eth.preInit() == true){
                gsm_current_state = GSM_JOIN;
            }
            break;
        case GSM_JOIN:
            printf(">>>JOIN\r\n");
            int join = eth.connect();
            if (join == false || join < 0){
                //stay here
            }
            else{
                //possibly send this sms to the main box at the lab
                //eth.send_SMS("17066311506", eth.getIPAddress());
                gsm_current_state = GSM_SERVER_IP;
            }
            break;
        case GSM_SERVER_IP:
            printf(">>>SERVER IP\r\n");
            serverIP = "api.pushingbox.com";
            if(serverIP != NULL)
            {
                gsm_current_state = GSM_CONNECT;
            }
            else{
                gsm_current_state = GSM_JOIN;
            } 
            break;
        case GSM_CONNECT:
            printf("\r\n>>>CONNECT TO: %s\r\n", serverIP);
            //sock.set_blocking(true,5000);
            if (sock.connect(serverIP,80) == true){
                gsm_current_state = GSM_SEND;
            }
            else{
                gsm_current_state = GSM_CONNECT;   
            }
            break;  
        case GSM_SEND:
            printf(">>>READY TO SEND\r\n");
            if(send){
            if(sock.send_all(gsm_header, sizeof(gsm_header)-1)){
                printf("Data succesfully sent to server\r\n");
                //close the connection so others can send too
                //wait(2);
                //eth.disconnect();
            }
            else{
                printf("Reconnecting to Server...\r\n");
                send = false;
                gsm_current_state = GSM_CONNECT;
            }
            }
            break;
        case GSM_WAIT:
            //check for text message from server asking for data
            gsm_current_state = GSM_SEND;
            break;
        default:
            pc.printf("This is a state error\r\n");
    }
}

//Initialize the GSM
void gsm_initialize(){ 
     wait(2.3); //Wait for the GSM to turn on properly before doing this initialization
      SIM_SCGC6 |= SIM_SCGC6_DMAMUX_MASK; //enabling dmamux clock
      SIM_SCGC7 |= SIM_SCGC7_DMA_MASK;  // enebaling dma clock
      //pc.printf("initializing DMA...\r\n");
     // control register mux, enabling uart3 receive
     DMAMUX_CHCFG0 |= DMAMUX_CHCFG_ENBL_MASK|DMAMUX_CHCFG_SOURCE(8); 
     
     // Enable request signal for channel 0 
     DMA_ERQ = DMA_ERQ_ERQ0_MASK;
     
      // select round-robin arbitration priority
     DMA_CR |= DMA_CR_ERCA_MASK;
     
     //enable error interrupt for DMA0 (commented out because we won't use interrupts for our implementation)
     //DMA_EEI = DMA_EEI_EEI0_MASK;
     
     //Address for buffer
     DMA_TCD0_SADDR = (uint32_t) &UART_D_REG(UART3_BASE_PTR);
     DMA_TCD0_DADDR = (uint32_t) buffer;
     // Set an offset for source and destination address
     DMA_TCD0_SOFF = 0x00; 
     DMA_TCD0_DOFF = 0x01; // Destination address offset of 1 byte per transaction
     
     // Set source and destination data transfer size
     DMA_TCD0_ATTR = DMA_ATTR_SSIZE(0) | DMA_ATTR_DSIZE(0);
     
     // Number of bytes to be transfered in each service request of the channel
     DMA_TCD0_NBYTES_MLNO = 0x01;
     // Current major iteration count
    DMA_TCD0_CITER_ELINKNO = DMA_CITER_ELINKNO_CITER(BUFFER_LENGTH);
    DMA_TCD0_BITER_ELINKNO = DMA_BITER_ELINKNO_BITER(BUFFER_LENGTH);
    // Adjustment value used to restore the source and destiny address to the initial value
    // After reading 'len' number of times, the DMA goes back to the beginning by subtracting len*2 from the address (going back to the original address)
    DMA_TCD0_SLAST = 0;   // Source address adjustment
    DMA_TCD0_DLASTSGA = -BUFFER_LENGTH;  // Destination address adjustment   
    // Setup control and status register
    DMA_TCD0_CSR = 0;
       
    // enable interrupt call at end of major loop
    DMA_TCD0_CSR |= DMA_CSR_INTMAJOR_MASK;
    
    //Activate dma transfer rx interrupt
    UART_C2_REG(UART3) |= UART_C2_RIE_MASK;
    UART_C5_REG(UART3) |= UART_C5_RDMAS_MASK | UART_C5_ILDMAS_MASK | UART_C5_LBKDDMAS_MASK;
    //activate p fifo register
    UART_PFIFO_REG(UART3) |= UART_PFIFO_RXFE_MASK; //RXFE and buffer size of 1 word
    queueInit();
    //pc.printf("done...\n\r");
}
 
//For debugging: print registers related to DMA and UART setup
void print_registers()
{
    pc.printf("\n\rDMA REGISTERS\n\r");
    pc.printf("DMA_MUX: 0x%08x\r\n",DMAMUX_CHCFG0);
    pc.printf("SADDR0: 0x%08x\r\n",DMA_TCD0_SADDR);
    pc.printf("DADDR0: 0x%08x\r\n",DMA_TCD0_DADDR);
    pc.printf("CITER0: 0x%08x\r\n",DMA_TCD0_CITER_ELINKNO);
    pc.printf("BITER0: 0x%08x\r\n",DMA_TCD0_BITER_ELINKNO);
    pc.printf("DMA_CR: %08x\r\n", DMA_CR);
    pc.printf("DMA_ES: %08x\r\n", DMA_ES);
    pc.printf("DMA_ERQ: %08x\r\n", DMA_ERQ);
    pc.printf("DMA_EEI: %08x\r\n", DMA_EEI);
    pc.printf("DMA_CEEI: %02x\r\n", DMA_CEEI);
    pc.printf("DMA_SEEI: %02x\r\n", DMA_SEEI);
    pc.printf("DMA_CERQ: %02x\r\n", DMA_CERQ);
    pc.printf("DMA_SERQ: %02x\r\n", DMA_SERQ);
    pc.printf("DMA_CDNE: %02x\r\n", DMA_CDNE);
    pc.printf("DMA_SSRT: %02x\r\n", DMA_SSRT);
    pc.printf("DMA_CERR: %02x\r\n", DMA_CERR);
    pc.printf("DMA_CINT: %02x\r\n", DMA_CINT);
    pc.printf("DMA_INT: %08x\r\n", DMA_INT);
    pc.printf("DMA_ERR: %08x\r\n", DMA_ERR);
    pc.printf("DMA_HRS: %08x\r\n", DMA_HRS);
    pc.printf("DMA_TCD0_DOFF: %08x\r\n",DMA_TCD0_DOFF);
    pc.printf("\n\rUART REGISTERS\n\r");
    pc.printf("UART_BDH_REG: %08x\r\n",UART_BDH_REG(UART3)); 
    pc.printf("UART_C1_REG: %08x\r\n",UART_C1_REG(UART3));
    pc.printf("UART_C2_REG: %08x\r\n",UART_C2_REG(UART3));
    pc.printf("UART_S1_REG: %08x\r\n",UART_S1_REG(UART3));
    pc.printf("UART_s2_REG: %08x\r\n",UART_S2_REG(UART3));  
    pc.printf("UART_C3_REG: %08x\r\n",UART_C3_REG(UART3));
    pc.printf("UART_D_REG: %08x\r\n",UART_D_REG(UART3));
    pc.printf("UART_MA1_REG: %08x\r\n",UART_MA1_REG(UART3));
    pc.printf("UART_MA2_REG: %08x\r\n",UART_MA2_REG(UART3));
    pc.printf("UART_C4_REG: %08x\r\n",UART_C4_REG(UART3));
    pc.printf("UART_C5_REG: %08x\r\n",UART_C5_REG(UART3));
    pc.printf("UART_ED_REG: %08x\r\n",UART_ED_REG(UART3));   
    pc.printf("UART_MODEM_REG: %08x\r\n",UART_MODEM_REG(UART3));
    pc.printf("UART_IR_REG: %08x\r\n",UART_IR_REG(UART3)); 
    pc.printf("UART_PFIFO_REG: %08x\r\n",UART_PFIFO_REG(UART3));
    pc.printf("UART_CFIFO_REG: %08x\r\n",UART_CFIFO_REG(UART3));
    pc.printf("UART_SFIFO_REG: %08x\r\n",UART_SFIFO_REG(UART3)); 
    pc.printf("UART_TWFIFO_REG: %08x\r\n",UART_TWFIFO_REG(UART3));
    pc.printf("UART_TCFIFO_REG: %08x\r\n",UART_TCFIFO_REG(UART3)); 
    pc.printf("UART_RWFIFO_REG: %08x\r\n",UART_RWFIFO_REG(UART3)); 
    pc.printf("UART_RCFIFO_REG: %08x\r\n",UART_RCFIFO_REG(UART3));
}