#include #include #include #include #include "delays.h" #include "configuration.h" #include "softuart.h" #include "tickcounter.h" #include "gprs.h" #include "gps.h" static uint32_t time_of_last_keepalive; static uint32_t time_of_last_transmit; void isr() __interrupt 0 { softuart_isr(); tickcounter_isr(); INTCONbits.RABIF = 0; // Ignore the port change interrupt, we only need it for wakeup. } // Turn the GPS & GSM power on static void set_power_on() { TRISBbits.TRISB6 = 0; PWR_ON = 1; } // Force GPS & GSM power off static void set_power_off() { TRISBbits.TRISB6 = 0; PWR_ON = 0; } // Allow external device to decide GPS & GSM power static void set_power_highz() { TRISBbits.TRISB6 = 1; } // Power-cycle the GSM to force reset it static void power_cycle() { delay_100ms(5); set_power_off(); delay_100ms(10); set_power_on(); delay_100ms(10); } // Go to power save mode for 268 seconds and wake up using WDT, // or if external device changes the state of the power control line. static void powersave() { uint8_t INTCON_save, PIE1_save; RCSTAbits.SPEN = 0; TRISCbits.TRISC7 = 1; TRISBbits.TRISB7 = 1; set_power_highz(); INTCONbits.GIE = 0; INTCON_save = INTCON; PIE1_save = PIE1; INTCON = PIE1 = 0; // Enable interrupt on power pin, which will wake us up when // communication is ongoing. INTCONbits.RABIE = 1; IOCBbits.IOCB6 = 1; __asm clrwdt sleep __endasm; TICKCOUNT += 268; // Watchdog period clrwdt(); INTCON = INTCON_save; PIE1 = PIE1_save; INTCONbits.GIE = 1; } // Send a status message with the latest GPS & system info static void send_message(const char *status) { bool success = false; if (gprs_dial()) { if (gprs_startrequest()) { gprs_putsrequest("STATUS: "); gprs_putsrequest(status); gprs_putcrequest('\n'); gprs_putsrequest("GPS: "); gprs_putsrequest(GPS_LINE); gprs_putcrequest('\n'); gprs_putsrequest("CELLID: "); gprs_putsrequest(GPRS_CELL_ID); gprs_putcrequest('\n'); gprs_putsrequest("TICKCOUNT: "); gprs_puthrequest(get_ticks()); gprs_putcrequest('\n'); gprs_putsrequest("TIMETOFIX: "); gprs_puthrequest(time_to_fix); gprs_putcrequest('\n'); gprs_putsrequest("TIME_SINCE_KEEPALIVE: "); gprs_puthrequest(get_ticks() - time_of_last_keepalive); gprs_putcrequest('\n'); gprs_putsrequest("BATTERY: "); gprs_putsrequest(GPRS_BATTERY_LEVEL); gprs_putcrequest('\n'); success = gprs_endrequest(); } } if (!success) { if (gsm_startsms()) { gsm_puts("GPS: "); gsm_puts(GPS_LINE); gsm_puts("\r\n"); gsm_puts("CELL: "); gsm_puts(GPRS_CELL_ID); success = gsm_endsms(); } } gprs_shutdown(); } // Try to get a GPS fix and then transmit our location static bool send_location(const char *status) { bool got_fix = gps_waitforfix(1800, true); if (got_fix) { clrwdt(); sleep(120); // Wait a moment for the fix to get more accurate gps_waitforfix(60, false); } send_message(status); return got_fix; } // Check if it is time to transmit location bool is_it_time_to_transmit() { uint32_t ticks = get_ticks(); uint32_t time_since_transmit = ticks - time_of_last_transmit; uint32_t time_since_keepalive = ticks - time_of_last_keepalive; if (time_since_keepalive < 3600) { return false; // Wait atleast an hour between keepalives } else if (time_since_keepalive < 86400) { return (time_since_transmit > 3600); // Transmit once an hour for the first 24 hours } else if (time_since_keepalive < 86400 * 7) { return (time_since_transmit > 3600 * 6); // Transmit every 6 hours for the first week } else if (time_since_keepalive < 86400 * 30) { return (time_since_transmit > 86400); // Transmit once a day for the first month } else { return (time_since_transmit > 86400 * 7); // Transmit once a week until the end of time } } void main() { OSCCON = 0b01110001; // 8 MHz internal osc ANSEL = ANSELH = 0; TRISA = TRISB = TRISC = 0xFF; WPUBbits.WPUB5 = 0; // No pull-up on RX pin WPUBbits.WPUB6 = 0; // No pull-up on power pin //TRISA_bits.TRISA0 = 0; // DEBUG //TRISA_bits.TRISA1 = 0; // DEBUG OPTION_REGbits.NOT_RABPU = 0; OPTION_REGbits.T0CS = 0; // TIMER 0 is for software uart OPTION_REGbits.INTEDG = 0; // INT is for detecting start bit // TIMER 1 is for tick counter, 1:4 prediv, i.e. 500kHz frequency TICKCOUNT = 0; T1CON = 0b00100001; // Watchdog with 1:65536 and 1:128 prescaler => 268 s timeout WDTCON = 0b00010111; clrwdt(); // Enable interrupts for tick counter & soft uart PIE1bits.TMR1IE = 1; INTCONbits.INTE = 1; INTCONbits.GIE = 1; INTCONbits.PEIE = 1; // USART: 115200 bps, 8N1, for GSM SPBRG = 16; SPBRGH = 0; BAUDCTLbits.BRG16 = 1; TXSTA = 0b00100110; RCSTA = 0b00010000; RCSTAbits.SPEN = 1; // Workaround SDCC bug of not initializing static variables on PIC. time_of_last_keepalive = 0; time_of_last_transmit = 0; GPS_LINE[0] = 0; GPRS_BATTERY_LEVEL[0] = 0; GPRS_CELL_ID[0] = 0; // Report that we have booted { power_cycle(); gps_waitforfix(15, true); // We may get a partial/old fix if we are lucky send_message("BOOT"); set_power_highz(); } while (1) { if (is_it_time_to_transmit()) { power_cycle(); send_location(""); set_power_highz(); time_of_last_transmit = get_ticks(); } if (PWR_ON == 1) { // External device is communicating with GPRS RCSTAbits.SPEN = 1; clrwdt(); if (gsm_expect("KEEPALIVE_n9rM", 120)) { time_of_last_keepalive = get_ticks(); } } else { // No activity, we can sleep powersave(); } } }