2022-11-01 11:22:55 +03:00

392 lines
9.7 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "config.h"
#include "platform.h"
#include <util/delay.h>
#include <avr/interrupt.h>
#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) {
const uint8_t old_exec = exec;
exec = -1;
MCUCR &= ~(1 << SE);
sei();
read_sensors();
// если измерений 6 (и мало ли больше), то отправляем смс
// если под скоростью, то тоже отправляем смс
if (old_exec == 2 || sensor_measurements >= MEASUREMENTS) {
try_to_send_telemetry();
}
cli();
MCUCR |= (1 << SE);
exec = 0;
}
}