#include "config.h" #include "platform.h" #include #include #define SMS_END "\032\n" #define SIM800_DELAY_TIME 100 //#define TARGET_PHONE "+79208109798" // мой номер #define TARGET_PHONE "+79536215150" // номер "Данила Меркунов Агромаг" #define MEASUREMENTS 6 uint8_t sensor_measurements = 0; char systick_execution_enable = 0; uint16_t sensor_1[MEASUREMENTS]; uint16_t sensor_2[MEASUREMENTS]; static volatile uint8_t timer0_time; ISR(TIMER0_OVF_vect) { timer0_time++; LED2_Toggle(); } uint8_t sim800_wait_for(PGM_P str) { if (timeout_err) { return -1; } PGM_P curr_pos = str; platform_wdt_start(); LED1_Set(); while (1) { char p = pgm_read_byte(curr_pos); if (p == '\0') { break; } char c = uart_read_char(); if (timeout_err) { break; } if (c == '\r') { continue; } if (c == p) { curr_pos++; } else { curr_pos = str; } } LED1_Reset(); platform_wdt_stop(); return timeout_err; } uint8_t sim800_wait_for_ok() { return sim800_wait_for(PSTR("OK\n")); } void sim800_start() { LED2_Set(); GSM_EN_Set(); _delay_ms(1000); // зажимаем кнопку на секунду GSM_KEY_Set(); _delay_ms(1100); GSM_KEY_Reset(); // еще 2 секунды на загрузку модуля _delay_ms(3000); // врубаем юарт uart_init(); uart_write_fstr(PSTR("AT\n")); if (sim800_wait_for_ok()) { return; } // вырубить echo mode (повторяет команду, которая прилетела) ATE0 _delay_ms(SIM800_DELAY_TIME); uart_write_fstr(PSTR("ATE1\n")); // TODO поставить 0 чтобы модем лишнюю херню не слал if (sim800_wait_for_ok()) { return; } // после готовности смс все сразу станет понятно if (sim800_wait_for(PSTR("SMS Ready\n"))) { return; } for (uint8_t i = 0; i < 40; i++) { _delay_ms(500); uart_write_fstr(PSTR("AT+CREG?\n")); if (sim800_wait_for(PSTR("+CREG: "))) { return; } char mode = uart_read_char(); uart_read_char(); // запятая char status = uart_read_char(); if (timeout_err) { return; } if (mode == '0' && status == '1') { return; } } timeout_err = 1; } void sim800_stop() { // вырубить модуль if (timeout_err) { uart_deinit(); GSM_KEY_Set(); _delay_ms(1100); GSM_KEY_Reset(); _delay_ms(500); } else { uart_write_fstr(PSTR("AT+CPOWD=1\n")); sim800_wait_for(PSTR("DOWN\n")); // придет NORMAL POWER DOWN uart_deinit(); } GSM_EN_Reset(); LED2_Reset(); } uint16_t sim800_get_battery() { _delay_ms(SIM800_DELAY_TIME); uart_write_fstr(PSTR("AT+CBC\n")); sim800_wait_for(PSTR("+CBC:")); for (uint8_t i = 0; i < 2; i++) { sim800_wait_for(PSTR(",")); } if (timeout_err) { return -1; } // по идее тут будет напряжение // 4 цифры, но мне не важно на самом деле сколько uint16_t result = 0; while (1) { char c = uart_read_char(); if (c == ' ' || c == '\r') { continue; } // туда попадет и символ конца строки if (c < '0' || c > '9') { break; } result *= 10; result += c - '0'; } // ждем ок, то есть конец команды sim800_wait_for_ok(); return result; } void sim800_prepare_sms() { _delay_ms(SIM800_DELAY_TIME); uart_write_fstr(PSTR("AT+CMGF=1\n")); // PDU режим sim800_wait_for_ok(); _delay_ms(SIM800_DELAY_TIME); uart_write_fstr(PSTR("AT+CMGS=\"" TARGET_PHONE "\"\n")); // PDU режим sim800_wait_for(PSTR(">")); } void sim800_wait_for_sms_send() { sim800_wait_for(PSTR("+CMGS")); } static void num2buff(char* buffer, uint16_t num) { int8_t len; // длинна числа if (num < 10) len = 1; else if (num < 100) len = 2; else if (num < 1000) len = 3; else if (num < 10000) len = 4; else len = 5; buffer[len] = '\0'; // вставляем конец строки for (; len > 0; len--) { uint8_t digit = (num % 10) + '0'; num /= 10; buffer[len - 1] = (char)digit; } } void sim800_send_telemetry() { uint16_t bat = sim800_get_battery(); sim800_prepare_sms(); if (timeout_err) { return; } char buff[6]; // sprintf(buff, "F1=%d F2=%d\033\n", sensor_1, sensor_2); _delay_ms(SIM800_DELAY_TIME); for (uint8_t i = 0; i < sensor_measurements; i++) { buff[0] = 'L'; buff[1] = (char)('0' + i); buff[2] = '='; buff[3] = '\0'; uart_write_str(buff); num2buff(buff, sensor_1[i]); uart_write_str(buff); buff[0] = ' '; buff[1] = 'R'; buff[2] = (char)('0' + i); buff[3] = '='; buff[4] = '\0'; uart_write_str(buff); num2buff(buff, sensor_2[i]); uart_write_str(buff); uart_write_char(' '); } // все измерения забрали uart_write_fstr(PSTR("BAT=")); num2buff(buff, bat); uart_write_str(buff); uart_write_fstr(PSTR(SMS_END)); sim800_wait_for_sms_send(); } void read_sensors() { timer0_time = 0; EXTPWR_EN_Set(); register uint32_t s1 = 0, s2 = 0; register uint8_t states = FRQ_Gpio & (FRQ1_Pin | FRQ2_Pin); TCNT0 = 0; TCCR0B |= (1 << CS02) | (1 << CS00); // x1024 while (timer0_time < 250) { uint8_t tmp = FRQ_Gpio; if ((tmp & FRQ1_Pin) != (states & FRQ1_Pin)) { states = (states & (~FRQ1_Pin)) | tmp; s1++; } if ((tmp & FRQ2_Pin) != (states & FRQ2_Pin)) { states = (states & (~FRQ2_Pin)) | tmp; s2++; } } TCCR0B &= ~((1 << CS02) | (1 << CS01) | (1 << CS00)); // x0 EXTPWR_EN_Reset(); // отрубаем питание генераторов // быстрое деление на 2 (считалось каждое изменение) // 64 секунды * 2 = 128 (2^7) sensor_1[sensor_measurements] = (uint16_t)(s1 >> 5); sensor_2[sensor_measurements] = (uint16_t)(s2 >> 5); sensor_measurements++; // готово! } int main() { platform_init(); LED2_Set(); _delay_ms(100); LED2_Reset(); _delay_ms(1000); // врубаем модем read_sensors(); for (uint8_t i = 0; i < 3; i++) { // рабочая отправка сообщений sim800_start(); sim800_prepare_sms(); _delay_ms(SIM800_DELAY_TIME); uart_write_fstr(PSTR("I'm working! Developed by Vlados31, PodvalTechnologies, HCC." SMS_END)); // сама смска sim800_wait_for_sms_send(); // отправляем сразу же телеметрию sim800_send_telemetry(); // рубим модем sim800_stop(); if (!timeout_err) { break; } else { _delay_ms(500); timeout_err = 0; } } sensor_measurements = 0; if (timeout_err) { for (;;) { _delay_ms(100); LED2_Toggle(); } } MCUCR |= (1 << SE); systick_execution_enable = 1; SP = RAMEND; asm volatile ( "main_loop:\n" "sleep\n" "rjmp main_loop\n"); } void try_to_send_telemetry() { for (uint8_t i = 0; i < 3; i++) { sim800_start(); sim800_send_telemetry(); sim800_stop(); if (!timeout_err) { break; } else { _delay_ms(500); // время между попытками timeout_err = 0; } } sensor_measurements = 0; } ISR(TIMER1_OVF_vect) { static uint16_t time = 0; static char exec = 0; if (systick_execution_enable) { time++; if (SPEED_Gpio & SPEED_Pin) { // (скорость отпущена, пин подтянут к питанию) // если скорости нет, шлем смс раз в час if (time > 60 * 60) { if (!exec) { time = 0; exec = 1; } } } else { // если скорость зажата, шлем смс каждые 5 минут с тем что есть if (time > 300) { if (!exec) { time = 0; exec = 2; } } } } if (exec > 0) { exec = -1; MCUCR &= ~(1 << SE); sei(); read_sensors(); // если измерений 6 (и мало ли больше), то отправляем смс // если под скоростью, то тоже отправляем смс if (exec == 2 || sensor_measurements >= MEASUREMENTS) { try_to_send_telemetry(); } cli(); MCUCR |= (1 << SE); exec = 0; } }