#include #include #include #include #include "log.h" #include "gprs.h" #include "gprs_config.h" #include "rtc.h" static void flush(SerialDriver *sd) { while (sdGetTimeout(sd, S2ST(1)) >= 0); } static const int TIMEOUT = S2ST(GPRS_TIMEOUT); static bool fgets_timeout(SerialDriver *sd, char *buf, size_t size) { char *buffer = buf; size--; // Space for trailing 0 while (size && sdReadTimeout(sd, (uint8_t*)buf, 1, TIMEOUT)) { if (*buf == '\n' || *buf == '\0') { *(++buf) = '\0'; LOG("Received: %s", buffer); return true; } buf++; size--; } *buf = '\0'; LOG("Read timeouted"); return false; } static bool fputs_timeout(SerialDriver *sd, const char *str) { LOG("Sending: %s", str); size_t size = strlen(str); bool status = (sdWriteTimeout(sd, (uint8_t*)str, size, TIMEOUT) == size); if (!status) LOG("fputs_timeout timeouted."); return status; } static bool expect(SerialDriver *sd, const char *expected) { char buffer[40]; while (fgets_timeout(sd, 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; } static bool update_rtc(SerialDriver *sd) { rtc_t time = {}; char buffer[40]; if (!fputs_timeout(sd, "AT+CTZU=1\r\n")) return false; // Example reply: +CTZU: 11/9/17 10:45:39 TimeZone: 33 while (fgets_timeout(sd, buffer, 40)) { if (strncmp(buffer, "+CTZU:", 6) == 0) { const char *delim = "/ :"; char *saveptr; time.year = atoi(strtok_r(buffer + 6, delim, &saveptr)) + 2000; time.month = atoi(strtok_r(NULL, delim, &saveptr)); time.day = atoi(strtok_r(NULL, delim, &saveptr)); time.hour = atoi(strtok_r(NULL, delim, &saveptr)); time.minute = atoi(strtok_r(NULL, delim, &saveptr)); time.second = atoi(strtok_r(NULL, delim, &saveptr)); break; } } if (time.year < 2011) return false; rtc_set(&time); return true; } bool http_connect(SerialDriver *sd) { return fputs_timeout(sd, "ATD*97#\r\n") && expect(sd, "OK") && fputs_timeout(sd, "CONNECT " RPC_SERVER " HTTP/1.1\r\n" "Host: " RPC_SERVER "\r\n\r\n") && expect(sd, "HTTP/1.1 200"); } static bool gprs_already_on = false; bool gprs_dial(SerialDriver *sd) { LOG("Starting to dial GPRS"); if (gprs_already_on) { // Try to disconnect and reconnect without rebooting the modem. LOG("Trying to disconnect old session"); chThdSleep(S2ST(1)); sdWriteTimeout(sd, (const uint8_t*)"+++", 3, TIME_IMMEDIATE); chThdSleep(S2ST(1)); if (fputs_timeout(sd, "AT\r\n") && expect(sd, "OK") && fputs_timeout(sd, "ATH\r\n") && expect(sd, "NO CARRIER") && http_connect(sd)) { LOG("GPRS reconnect succeeded"); flush(sd); return true; } else { gprs_already_on = false; } } // Turn off power to gprs module and then turn it back on palSetPadMode(GPRS_POWER_PORT, GPRS_POWER_PAD, PAL_MODE_OUTPUT_PUSHPULL); palSetPad(GPRS_POWER_PORT, GPRS_POWER_PAD); chThdSleep(MS2ST(2000)); palClearPad(GPRS_POWER_PORT, GPRS_POWER_PAD); // Send the power-on pulse palClearPad(GPRS_USART_PORT, GPRS_TX_PAD); palSetPadMode(GPRS_USART_PORT, GPRS_TX_PAD, PAL_MODE_OUTPUT_PUSHPULL); chThdSleep(MS2ST(200)); palSetPadMode(GPRS_USART_PORT, GPRS_TX_PAD, PAL_MODE_STM32_ALTERNATE_PUSHPULL); // Give the module time to wake up chThdSleep(MS2ST(5000)); int retries = 0; do { if (retries++ > 5) { LOG("5 retries exceeded\n"); return false; } chThdSleep(MS2ST(5000)); flush(sd); } while (!( fputs_timeout(sd, "AT\r\n") && expect(sd, "OK") && fputs_timeout(sd, "AT+CPIN=\"" GPRS_PIN_CODE "\"\r\n") && expect(sd, "OK") && fputs_timeout(sd, "AT+COPS=0\r\n") && expect(sd, "OK"))); if (update_rtc(sd)) LOG("RTC update OK\n"); else LOG("RTC update failed\n"); if (fputs_timeout(sd, "AT$TIMEOUT=100\r\n") && expect(sd, "OK") && fputs_timeout(sd, "AT+CGDCONT=" GPRS_APN "\r\n") && expect(sd, "OK") && fputs_timeout(sd, "AT$DESTINFO=" GPRS_PROXY "\r\n") && expect(sd, "OK") && http_connect(sd)) { LOG("GPRS dial succeeded"); gprs_already_on = true; flush(sd); return true; } else { LOG("GPRS dial failed"); return false; } }