#include #include #include #include "delays.h" #include "configuration.h" #include "tickcounter.h" #include "gprs_config.h" // This is file-scope to conserve RAM. static uint16_t start; // Wait for string in input, up to timeout seconds. bool gsm_expect(const char *expected, uint8_t timeout) { uint8_t pos = 0; start = get_ticks16(); while (expected[pos]) { while (!PIR1bits.RCIF) { if (get_ticks16() - start > timeout) return false; } if (expected[pos++] != (char)RCREG) pos = 0; // Mismatch, restart from beginning } return true; } void sleep(uint8_t seconds) { start = get_ticks16(); while (get_ticks16() - start < seconds); } static void gsm_flush() { RCSTAbits.CREN = 0; __asm banksel RCREG movf RCREG, W movf RCREG, W __endasm; RCSTAbits.CREN = 1; } // Write a string to GSM bool gsm_puts(const char *p) { while (*p) { while (!PIR1bits.TXIF); TXREG = *p++; } gsm_flush(); // Clear overflow error due to echo return true; } // Start SMS sending bool gsm_startsms() { gsm_puts("AT+CMGF=1\r\n"); if (!gsm_expect("OK", 5)) return false; sleep(5); gsm_puts("AT+CMGS=\"" SMS_NUMBER "\"\r\n"); return gsm_expect(">", 15); } bool gsm_endsms() { gsm_puts("\r\n\x1a"); return gsm_expect("OK", 15); } char GPRS_BATTERY_LEVEL[6]; static bool gsm_batterylevel() { uint8_t pos = 0; start = get_ticks16(); GPRS_BATTERY_LEVEL[0] = 0; gsm_puts("AT+CBC\r\n"); if (!gsm_expect("\n+CBC: ", 5)) return false; do { while (!PIR1bits.RCIF) { if (get_ticks16() - start > 5) return false; } GPRS_BATTERY_LEVEL[pos++] = RCREG; } while (GPRS_BATTERY_LEVEL[pos - 1] != '\n' && pos < 6); GPRS_BATTERY_LEVEL[pos - 1] = 0; return gsm_expect("OK", 5); } char GPRS_CELL_ID[9]; // Wait for GSM connection and record cell id static bool gsm_wait_connection() { uint8_t i, byte; GPRS_CELL_ID[0] = 0; gsm_puts("AT+CREG=2\r\n"); i = 0; while (!(gsm_puts("AT+CREG?\r\n") && gsm_expect("+CREG: 2, 1", 5))) { if (i++ > 30) return false; } i = 0; while (i < 8) { while (!PIR1bits.RCIF) { if (get_ticks16() - start > 5) return false; } byte = RCREG; if (byte >= '0') GPRS_CELL_ID[i++] = byte; else if (byte == '\n') break; } GPRS_CELL_ID[i] = 0; return true; } bool gprs_dial() { uint8_t retries = 0; clrwdt(); // Send the power-on pulse RCSTAbits.SPEN = 0; TRISBbits.TRISB7 = 0; GSM_TX = 0; delay_100ms(2); RCSTAbits.SPEN = 1; TRISBbits.TRISB7 = 1; // Assert CTS TRISCbits.TRISC7 = 0; GSM_CTS = 0; // Give the module time to wake up sleep(2); // Perform auto-baud initialization retries = 0; while (!(gsm_puts("AT\r\n") && gsm_expect("OK", 5))) { if (retries++ > 5) return false; } // Wait for GSM network connection gsm_wait_connection(); // Get battery level information gsm_batterylevel(); // Program the GPRS destination info if (gsm_puts("AT+CGDCONT=" GPRS_APN "\r\n") && gsm_expect("OK", FAST_TIMEOUT) && gsm_puts("AT$DESTINFO=" GPRS_PROXY "\r\n") && gsm_expect("OK", FAST_TIMEOUT)) { return true; } else { return false; } } // To post data, we use up to 255 byte HTTP requests static uint8_t request_length; bool gprs_startrequest() { uint8_t tries = 0; do { if (tries++ > 3) return false; gsm_puts("AT\r\n"); } while (!gsm_expect("OK", FAST_TIMEOUT)); gsm_puts("ATD*97#\r\n"); if (!gsm_expect("OK", GPRS_TIMEOUT)) return false; gsm_puts("POST " TRACKER_URL " HTTP/1.0\r\n"); gsm_puts("Content-Length: 255\r\n\r\n"); request_length = 255; return true; } // Put character void gprs_putcrequest(char b) { while (!PIR1bits.TXIF); TXREG = b; request_length--; } // Put string void gprs_putsrequest(const char *p) { while (*p) { while (!PIR1bits.TXIF); TXREG = *p++; request_length--; } } // Put hex value void gprs_puthrequest(uint32_t w) { uint8_t digit, pos; for (pos = 0; pos < 8; pos++) { digit = (w >> 28) & 15; if (digit >= 10) gprs_putcrequest('A' - 10 + digit); else gprs_putcrequest('0' + digit); w <<= 4; } } bool gprs_endrequest() { while (request_length) { gprs_putcrequest(' '); } gsm_puts("\r\n"); return gsm_expect("HTTP/1.0 200", GPRS_TIMEOUT); } void gprs_shutdown() { gsm_puts("AT$POWEROFF\r\n"); sleep(2); gsm_puts("AT$POWEROFF\r\n"); sleep(2); TRISCbits.TRISC7 = 1; }