392 lines
9.7 KiB
C
392 lines
9.7 KiB
C
#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;
|
||
}
|
||
}
|