/* Minimal GPRS dialer used from bootloader and crash handler. * Also handles some system initialization, such as setting clock speed. */ #include "gprs_config.h" #include "mini_gprs.h" #include "utils.h" #include "gpio.h" DECLARE_GPIO(power, GPRS_POWER_PORT, GPRS_POWER_PAD); DECLARE_GPIO(tx, GPRS_USART_PORT, GPRS_TX_PAD); DECLARE_GPIO(rx, GPRS_USART_PORT, GPRS_RX_PAD); DECLARE_GPIO(cts, GPRS_USART_PORT, GPRS_CTS_PAD); DECLARE_GPIO(rts, GPRS_USART_PORT, GPRS_RTS_PAD); DECLARE_GPIO(logtx, GPIOA, 9); #define CLOCK_FREQ 8000000 void system_init() { // Set clock speed RCC->CR |= RCC_CR_HSION; // HSI on while (!(RCC->CR & RCC_CR_HSIRDY)); // Wait for PLL RCC->CFGR = RCC_CFGR_SW_HSI; // Switch clock // Enable peripherals RCC->APB1ENR |= RCC_APB1ENR_USART3EN | RCC_APB1ENR_TIM6EN; RCC->APB2ENR |= RCC_APB2ENR_USART1EN | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN; // GPRS_USART: 115200bps 8N1 RTS/CTS GPRS_USART->BRR = (CLOCK_FREQ / 115200) | 1; GPRS_USART->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE; GPRS_USART->CR3 = USART_CR3_CTSE | USART_CR3_RTSE; // USART1: 115200bps 8N1 transmit only USART1->BRR = (CLOCK_FREQ / 115200) | 1; USART1->CR1 = USART_CR1_UE | USART_CR1_TE; // TIM6: increment at 1000 Hz. TIM6->CR1 = TIM_CR1_CEN; TIM6->CR2 = 0; TIM6->ARR = 65535; TIM6->PSC = CLOCK_FREQ / 1000 - 1; TIM6->CNT = 0; // Configure IO pins gpio_power_mode(GPIO_OUT_10); gpio_tx_mode(GPIO_AFOUT_10); gpio_rx_mode(GPIO_HIGHZ_INPUT); gpio_cts_mode(GPIO_HIGHZ_INPUT); gpio_rts_mode(GPIO_AFOUT_10); gpio_logtx_mode(GPIO_AFOUT_10); } void mini_LOG(const char *message) { const char *p = message; while (*p) { while(!(USART1->SR & USART_SR_TXE)); USART1->DR=*p; p++; } while(!(USART1->SR & USART_SR_TXE)); USART1->DR='\n'; } // Get ticks, in 1000 Hz units. static uint16_t get_time() { return TIM6->CNT; } static void sleep(int ms) { uint16_t start = get_time(); while ((get_time() - start) < ms); } static bool timeouted(uint16_t start_time) { return (uint16_t)(get_time() - start_time) > 1000 * GPRS_TIMEOUT; } static void _flush() { uint16_t time = get_time(); do { if (GPRS_USART->SR & USART_SR_RXNE) { always_read(GPRS_USART->DR); time = get_time(); } } while (get_time() - time < 1000); } static bool _gets(char *buf, int size) { uint16_t time = get_time(); char *buffer = buf; size--; // Space for trailing 0 while (size) { while (!(GPRS_USART->SR & USART_SR_RXNE)) { if (timeouted(time)) { mini_LOG("Read timeouted"); return false; } } *buf = GPRS_USART->DR; if (*buf == '\n' || *buf == '\0') { *(++buf) = '\0'; mini_LOG(buffer); return true; } buf++; size--; } *buf = '\0'; mini_LOG("Read overflowed"); return false; } static bool _puts(const char *str) { uint16_t time = get_time(); const char *p = str; mini_LOG(str); while (*p) { while(!(GPRS_USART->SR & USART_SR_TXE)) { if (timeouted(time)) return false; } GPRS_USART->DR=*p; p++; } return true; } static bool write(char *buffer, int size) { uint16_t time = get_time(); const char *p = buffer; while (size) { while(!(GPRS_USART->SR & USART_SR_TXE)) { if (timeouted(time)) return false; } GPRS_USART->DR=*p; time = get_time(); p++; size--; if (size % 100 == 0) sleep(100); } return true; } static int strncmp(const char *s1, const char *s2, int n) { const unsigned char *c1 = (const unsigned char *)s1; const unsigned char *c2 = (const unsigned char *)s2; unsigned char ch; int d = 0; while (n--) { d = (int)(ch = *c1++) - (int)*c2++; if (d || !ch) break; } return d; } static int strlen(const char *s) { const char *ss = s; while (*ss) ss++; return ss - s; } static bool expect(const char *expected) { static char buffer[40]; while (_gets(buffer, 40)) { if (strncmp(buffer, expected, strlen(expected)) == 0) return true; if (strncmp(buffer, "ERROR", 5) == 0 || strncmp(buffer, "NO CARRIER", 10) == 0 || strncmp(buffer, "BUSY", 4) == 0 || strncmp(buffer, "HTTP/1.1", 8) == 0) { return false; } } return false; } bool mini_gprs_dial() { mini_LOG("Starting GPRS dial"); // Turn off power and turn back on (note: active low) gpio_power_set(true); sleep(2000); gpio_power_set(false); // Send the power-on pulse gpio_tx_mode(GPIO_OUT_10); gpio_tx_set(false); sleep(100); gpio_tx_mode(GPIO_AFOUT_10); // Give the module time to wake up sleep(5000); int retries = 0; do { if (retries++ > 3) { mini_LOG("3 retries exceeded"); return false; } sleep(5000); _flush(); } while (!( _puts("AT\r\n") && expect("OK") && _puts("AT+CPIN=\"" GPRS_PIN_CODE "\"\r\n") && expect("OK") && _puts("AT+COPS=0\r\n") && expect("OK"))); if (_puts("AT+CGDCONT=" GPRS_APN "\r\n") && expect("OK") && _puts("AT$DESTINFO=" GPRS_PROXY "\r\n") && expect("OK")) { mini_LOG("GPRS dial succeeded"); return true; } else { return false; } } #define DUMP_START 0x20000000 #define DUMP_LENGTH 8192 #define STR2(x) #x #define STR(x) STR2(x) bool upload_crashdump() { if (!(_puts("ATD*97#\r\n") && expect("OK"))) return false; _flush(); if (_puts("POST " CRASHDUMP_URL " HTTP/1.0\r\n") && _puts("Content-Length: 3000\r\n\r\n") && write((char*)DUMP_START, DUMP_LENGTH) && _puts("\r\n") && expect("HTTP/1.0 200")) { return true; } else { return false; } }