помогите избавится от "string"

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

Здравствуйте, не знаю пока нужен скетч или нет, нужен выложу, но он более 2500 строк... проблемма такая, программа работает хорошо, но хочу оптимизацию и дополнительное место для будущей можернизации устройства... и для этого хочу отказатся от стрингов :) жмут заразы. скетч без них занимает 1060 динамической памяти а с ними 1526... 

что делаю с этими строками:

1) забиваю строку с модема m590e

2) проверяю совпадают ли строки

3) отправляю смс

понимаю надо использховать массивы char[] но каким образом пока не могу понять

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015


#include <EEPROM.h>
#include <SoftwareSerial.h>
SoftwareSerial myGSM(3, 4);          // RX3, TX4

#define MY_GSM Serial
//#define MY_GSM myGSM

#define OPEN "open"
#define SIGNAL "signal"
#define SIRENA_ON "sirena"
#define RUCHNAYA "ruchnaya"
#define AVTOMAT "avtomat"
#define CLOSED "closed"
#define TRUNK "trunk"
#define SETUP "setup"
#define HARD_RESET "reset"
#define SBROS_NASTROEK "sbros"
#define WRITE1 "write1"
#define WRITE2 "write2"
#define WRITE3 "write3"
#define START_ON "start"
#define START_OFF "stop"
#define SRABOTKA_DVERI 1500 //время сработки активаторов дверей
#define ENGINE_START_MAX_TIME 4 //В секундах масимальное время работы стартера типично 3 -10 сек
#define ENGINE_WARM_TIME 1200000 //В миллисекундах время работы мотора после запуска 1200000 миллисекунд = 20 минут
#define ZADERZHKA_LOG_NETRAL 600000 //задержка логической нейтрали
#define DELTA  500 //задаем ffвремя для расброса времени посылаемого сигнала
#define DELTA1  3400 //задаем время для расброса времени посылаемого сигнала
#define RXD 2


#define PASSWORD "password"
#define KOD_BRELKA1 111111
#define KOD_BRELKA 111111111         // код брелка
#define KOD_KNOPKI_OPEN 13
#define KOD_KNOPKI_CLOSED 14
#define KOD_KNOPKI_CHANEL 11
#define KOD_KNOPKI_ZAPUSK 7

#define HAND_BRAKE_IN A3 // геркон на КПП "-"
#define SHARGING_IN A2  //генератор
#define KONCEVIKI A5// концевики дверей
#define SHOCK_SENSOR_LOW A4
#define SHOCK_SENSOR_HIGH A4
#define PIN_ZAZHIGANIYA A1


#define ENGINE_OUT 9  //d9 adruino зажигание
#define STARTER_OUT 14  //A0 adruino реле стартера
#define POVOROT_OUT 6 //  d6 поворотники
#define SECPOWER_OUT 11  //d11 цепи вторичного питания печка, фары итд
#define DOOR_CLOSE 8// d8 реле закрытия дверей
#define SIRENA 7
#define DOOR_OPEN 12// d12реле открытия дверей
#define STATUS_OUT 13  //d13 светодиод статуса системы  горит = система готова к работе(включена, ручник стоит). одно мигание запущен с первой попытки 2 со второй 3 с третьей
#define BAGAZHNIK_OUT 10// d9 багажник
#define DOP_RELEY 5// дополнительное реле на выход


boolean  rucnik_OFF = 1;
boolean actual_mode = 0;
boolean allow_start = 0;
boolean chanel_button = 0;
boolean close_button = 0;
boolean dveri_otkrili = 0;
boolean flag_blink = 1;
boolean flag_securiti = 0;
boolean flag_securiti_1 = 0;
boolean flag_security_konceviki = 1;
boolean flag_set_status_led = 1;
boolean flag_sirena_high = 0;
boolean flag_sirena_millis = 0;
boolean GO = 0;
boolean hand_brake_else_plus = 1; // "1" - Когда стоит на скорости то замыкается на массу, "0" - Кода стоит на скорости то нет замыкания на массу
boolean hand_brake_if_plus = 1; // "1" - Когда стоит на скорости то замыкается на массу, "0" - Кода стоит на скорости то нет замыкания на массу
boolean log_netral_gotov = 0;
boolean ne_zapusk = 0;
boolean obnulenie = 1;
boolean open_button = 0;
boolean ot_sms = 0;
boolean otmetka_skorosty = 0;
boolean otmetka2 = 0;
boolean otmetka3 = 0;
boolean otschet_poshel = 0;
boolean proverka_reset = 0;
boolean proverka_skorosty1 = 0;
boolean razriv = 0;
boolean rezreshil_proverku = 1;
boolean ruchnaya_kpp = 0;
boolean sbros_miganiya = 0;
boolean securiti = 0;
boolean sharnging_else_plus = 1; // "1" - Если на генераторе при заведенном двигателе +12В , "0" - Если на генераторе при заведенном двигателе 0В
boolean sharnging_if_plus = 1; // "1" - Если на генераторе при заведенном двигателе +12В , "0" - Если на генераторе при заведенном двигателе 0В
boolean sirena_program = 0;
boolean srabotka_koncevikov = 0;
boolean vikluchil = 0;
boolean warring_security = 0;
byte zapis1 = 0;
boolean zapusk_button = 0;
boolean zapusk_off = 0;
byte Button_code;
byte dlya_ruchnika = 0;
byte flag_zakrit = 0;
byte flash_count = 0;
byte i = 0;
byte l = 0;
byte left_start_try = 0;
byte otmena_povtora = 10;
byte otmena_svecheniya = 0;
byte otmetka1 = 0;
byte proverka_pered_otpravkoi_1 = 0;
byte rcvd_err = 0; //флаг наличия ошибки приема
byte received = 0; //флаг наличия принятой инфы

char ch = 0;
char data = 0;
char flag_dva = 3;
char flag_dva_sirena = 3;
const int buflen = 200;
int c = 0;
int gena = 0;
int gena1 = 0;
int generator_konec = 0;
int generator_nashalo = 0;
int generator_seredina = 0;
int HAND_BRAKE_ON = 0; //  значение входа ручника
int ne_zapusk1 = 5;
int ruchik_konec = 0;
int ruchik_nachalo = 0;
int ruchik_seredina = 0;
int SHARGING_ON = 0; // значение входа генератора
static unsigned long big_interval = 0;
static unsigned long flash_interval = 0;
String   val = "";
String MASTER_status = "";
String phone1 = "";
String phone2 = "";
String phone3 = "";
uint32_t code = 0UL; // собственно принятая инфа
uint32_t RC_code;
unsigned int h = 0;
unsigned int time, oldtime; //переменные для времени
unsigned long delay_millis_sirena_high = 0;
unsigned long dlya_miganiya = 0;
unsigned long dlya_sekund_dveri = 0; // для хранения секнд сработки дверей
unsigned long flag_raz = 0;
unsigned long flag_raz_sirena = 0;
unsigned long last_start_time = 0; //время в тысячных секунды когда был запущен движок
unsigned long millis_dor_close = 0;
unsigned long otschet_neitrali = 0;
unsigned long reset_modem_millis = 0;
unsigned long sekunda_skoroty = 0;
unsigned long sekunda_skoroty_sirena = 0;
unsigned long set_time_call = 0;

char buf[buflen];
void setup() {
  pinMode(POVOROT_OUT, OUTPUT); // enable output
  POVOROT_OUT_HIGH();
  pinMode(SIRENA, OUTPUT); // enable output
  pinMode(STARTER_OUT, OUTPUT); // enable output
  pinMode(ENGINE_OUT, OUTPUT); // enable output
  pinMode(SECPOWER_OUT, OUTPUT); // enable output
  pinMode(STATUS_OUT, OUTPUT); // enable output
  pinMode(BAGAZHNIK_OUT, OUTPUT); // enable output
  pinMode(DOOR_OPEN, OUTPUT); // enable output
  pinMode(DOOR_CLOSE, OUTPUT); // enable output
  pinMode(DOP_RELEY, OUTPUT);
  nastroyki();
  readi_modem();

}
void sms_zapusk_nevozmozhen()
{
  sms("ustanovki ne sohraneni, zapusk nevozmozhen", MASTER_status);
}
void sms_esli_stoit_na_skorosti()
{
  sms("stoit na skorosti", MASTER_status);
}
void sms_esli_popytki_zapuska_konchilis()
{
  sms("popytki zapyska konchilis'", MASTER_status);
}
void sms_esli_uhe_zavedena()
{
  sms("uzhe zavedena", MASTER_status);
}
void sms_esli_zavedena_uspeshno()
{
  sms("zavedena uspeshno", MASTER_status);
}
void sms_esli_zaglushen_uspeshno()
{
  sms("zaglushen uspeshno", MASTER_status);
}
void loop()
{

  if (MY_GSM.available() )   {     //есть данные от GSM модуля
    i = 0;
    while (i < 131)
    { buf[i] = '\0';
      i++;
    }
    val = "";

    i = 0;
    while (MY_GSM.available()) {
      ch = MY_GSM.read();
      delay(10);
      buf[i] = ch;
      val += ch;
      i++;
    }
    Serial.println(val);
    buf[i] = '\0';
    delay(100);
  }
  sms_start_stop();
  if (securiti == 1)
  {
    proverka_securiti();
    flag_securiti = 1;
    if (sirena_program == 1) {
      sirena_prerivanie();
    }
  }
  else if (securiti == 0 && flag_securiti == 1 && flag_securiti_1 == 1)
  {
    flag_securiti_1 = 0;
    flag_securiti = 0;
    POVOROT_OUT_LOW();
    SIRENA_LOW();
    rucnik_OFF = 0;
    do_shutdown();
    left_start_try = 0;
    last_start_time = 0;
  }
  if (ne_zapusk == 1)
  {

    zvonok_zapuska();
  }
  if (actual_mode != 0 )
  {
    check_for_shutdown();
  }
  set_status_led();
  if (rezreshil_proverku == 1 && actual_mode == 0)
  {
    proverka_skoroti();
  }
  drevi_off();
  button();
  if (flag_raz >= 1) {
    Miganie();
  }
  kakaya_knopka();
  migaem_raz();
  obnulenie_millis();
  if (warring_security == 1)
  {
    if (millis() >= (set_time_call + 20000))
    {
      sbros();
      delay(500);
      zvonok();
      delay(200);
      set_time_call = millis();
    }
    if (hand_brake_if_plus == 1) {
      if (analogRead(HAND_BRAKE_IN) > HAND_BRAKE_ON)
      {
        hand_brake_funkcion();
      }
    }
    else if (hand_brake_if_plus == 0) {
      if (analogRead(HAND_BRAKE_IN) <= HAND_BRAKE_ON)
      {
        hand_brake_funkcion();
      }
    }
  }
  reset_modem();
  if ((ruchnaya_kpp == 1) && (log_netral_gotov == 0) && (actual_mode == 0))
  {
    log_netral();
  }
  if (val != "")
  {
    // Serial.println(val);
    val = "";
  }

}
void hand_brake_funkcion()
{
  dlya_ruchnika++;
  if (dlya_ruchnika == 25)
  {
    POVOROT_OUT_LOW();
    rucnik_OFF = 0;
    do_shutdown();
    left_start_try = 0; // и больше не заводим
    actual_mode = 0;
    dlya_ruchnika = 0;
  }
}
void obnulenie_millis()
{
  if (millis() > 11000)
  {
    obnulenie = 0;
  }
  if (millis() > 0 && millis() < 10000 && obnulenie == 0)
  {
    obnulenie = 1;
    proverka_pered_otpravkoi(); c = 0;
    while (c <= 3) {
      sms("BPEM9 O6HyJIuJIoCb", MASTER_status);
      proverka_modema();
    }
    if (millis() < big_interval) {
      big_interval = 0;
    }
    if (millis() < flash_interval)
    {
      flash_interval = 0;
    }
    if (millis() < last_start_time)
    {
      last_start_time = 0;
    }
    if (millis() < sekunda_skoroty)
    {
      sekunda_skoroty = 0;
    }
    if (millis() < set_time_call)
    {
      set_time_call = 0;
    }
    if (millis() < dlya_sekund_dveri)
    {
      dlya_sekund_dveri = 0;
    }
    if (millis() < dlya_miganiya)
    {
      dlya_miganiya = 0;
    }
    if (millis() < delay_millis_sirena_high)
    {
      delay_millis_sirena_high = 0;
    }
    if (millis() < millis_dor_close)
    {
      millis_dor_close = 0;
    }
  }
}
void proverka_modema()
{
  c++;
  delay(1000);
  int p = 0;
  if (val.indexOf("OK") > -1)
  {
    c = 4;
  }
  else
  {
    for (; p < 11;)
    {
      delay(200);
      if (MY_GSM.available() )   {     //есть данные от GSM модуля
        i = 0;
        while (i < 131)
        { buf[i] = '\0';
          i++;
          val = "";
        }
        i = 0;
        while (MY_GSM.available()) {
          ch = MY_GSM.read();
          delay(10);
          buf[i] = ch;
          val += ch;
          i++;
        }
        buf[i] = '\0';
        Serial.println(val);
      }
      p++;
      if (val.indexOf("OK") > -1)
      {
        c = 4;
        return;
      }

      else if ((p == 10) || (val.indexOf("ERROR") > -1))
      {
        return;
      }
    }
  }
}
void nezapusk_plus()
{
  delay(200);
  sbros();
  delay(500);
  zvonok();
  delay(200);
  set_time_call = millis();
  ne_zapusk1++;
}
void zvonok_zapuska()
{
  if (ne_zapusk1 < 5) {
    if (val.indexOf("+CLIP") > -1)
    {
      ne_zapusk1++;
      delay(200);
      sbros();
    }
    else if   ((val.indexOf("CONNECT") > -1) )
    {
      delay(200);
      sbros();
      ne_zapusk = 0;
      set_time_call = millis();
    }
    else if (val.indexOf("NO CARRIER") > -1)  {
      nezapusk_plus();
    }
    else if (val.indexOf("NO ANSWER") > -1)  {
      nezapusk_plus();
    }
    else  if (val.indexOf("BUSY") > -1)  {
      nezapusk_plus();
    }
    else if (millis() >= (set_time_call + 20000))
    {
      nezapusk_plus();
    }
  }
  else
  {
    ne_zapusk1 = 5;
    ne_zapusk = 0;
    proverka_pered_otpravkoi(); c = 0;
    while (c <= 3) {
      sms("mashina zavedena, dozvon neudalsya", MASTER_status);
      proverka_modema();
    }
  }
}
void had_brake_proverka()
{
  rucnik_OFF = 0;
  do_shutdown();
  actual_mode = 1; // заканчиваем попытки запустить движок
  left_start_try = 0; //без ручника другие попытки бесполезны
  if  (razriv == 0)
  {
    proverka_pered_otpravkoi(); c = 0;
    while (c <= 3) {
      sms_esli_stoit_na_skorosti();
      proverka_modema();
    }
    razriv = 1;
  }
}
void sharnging_proverka()
{
  ENGINE_OUT_HIGH();//включаем зажигание
  POVOROT_OUT_HIGH();
  delay(1500);
  POVOROT_OUT_LOW();
  delay(1500); // останавливаем код на 3 секунды чтобы бензонасос набрал давление, все датчики включились
  do_start();
  if (left_start_try == 0 )
  {
    delay(200);
    if  (razriv == 0)
    {
      proverka_pered_otpravkoi(); c = 0;
      while (c <= 3) {
        sms_esli_popytki_zapuska_konchilis();
        proverka_modema();
      }
      razriv = 1;
    }
    delay(200);
    POVOROT_OUT_LOW();
    SIRENA_LOW();
    rucnik_OFF = 0;
    do_shutdown();
    left_start_try = 0;
    actual_mode = 0;  // движок выключили запомним это
    last_start_time = 0; // ну и забудем о том что он был включен
  }
}
void sharnging_else_proverka()
{

  actual_mode = 1;  // движок выключили запомним это
  last_start_time = 0; // ну и забудем о том что он был включен
  delay(200);
  if (razriv == 0)
  {
    proverka_pered_otpravkoi(); c = 0;
    while (c <= 3) {
      sms_esli_uhe_zavedena();
      proverka_modema();
    }
    razriv = 1;
  }
  delay(200);
}
void check_start()
{
  zapusk_off = 1;
  gena = 0;
  gena1 = 0;
  if ( left_start_try > 0)
  {
    if (hand_brake_if_plus == 1) {
      if ((analogRead(HAND_BRAKE_IN) > HAND_BRAKE_ON ) && (ruchnaya_kpp == 0) ) //без ручника не делаем запуск
      {
        had_brake_proverka();
        return;
      }
      else if ( (ruchnaya_kpp == 1) && (log_netral_gotov == 0)) //без ручника не делаем запуск
      {
        had_brake_proverka();
        return;
      }
    }
    else if (hand_brake_if_plus == 0) {
      if ((analogRead(HAND_BRAKE_IN) <= HAND_BRAKE_ON ) && (ruchnaya_kpp == 0)) //без ручника не делаем запуск
      {
        had_brake_proverka();
        return;
      }
      else if ( (ruchnaya_kpp == 1) && (log_netral_gotov == 0)) //без ручника не делаем запуск
      {
        had_brake_proverka();
        return;
      }
    }
    if (sharnging_else_plus == 1) {
      proverka_geni();
      if (gena <= SHARGING_ON  )    // проверяем что генератор не работает
      {
        sharnging_proverka();
      }
      else
      {
        sharnging_else_proverka();
      }
    }
    else if (sharnging_else_plus == 0) {
      proverka_geni();
      if (gena > SHARGING_ON  )    // проверяем что генератор не работает
      {
        sharnging_proverka();
      }
      else
      {
        sharnging_else_proverka();
      }
    }
  }
}
void do_start()
{
  gena = 0;
  gena1 = 0;
  SECPOWER_OUT_LOW(); //выключаем печку фары итд
  left_start_try-- ;
  STARTER_OUT_HIGH(); //включаем стартер
  for (int secs = 0; secs <= (ENGINE_START_MAX_TIME * 5) ; secs++) //
  {
    delay(200); // и продолжаем его держать включенным 1 секунду
    if (sharnging_if_plus == 1)
    {
      proverka_geni();
      if (gena > SHARGING_ON) //если зарядка пошла то
      {
        break;  // прерываем цикл
      }
    }
    else if (sharnging_if_plus == 0)
    {
      proverka_geni();
      if (gena <= SHARGING_ON) //если зарядка пошла то
      {
        break;  // прерываем цикл
      }
    }
  }
  STARTER_OUT_LOW(); //отключаем стартер
  if (sharnging_if_plus == 1) {
    proverka_geni();
    if (gena >= SHARGING_ON) //еще раз смотрим что  зарядка пошла
    {
      actual_mode = 1; //Запоминаем что движок запущен
      razriv = 0;
      last_start_time = millis(); // запоминаем время запуска движка
      flash_count = 4 - left_start_try;
    }
    else
    {
      ENGINE_OUT_LOW();   //выключаем зажигание чтбы разблокировать реле стартера
      SECPOWER_OUT_LOW(); //выключаем печку фары итд
      delay(2000);
      if ( left_start_try > 0)
      {
        check_start();
      }
    }
  }
  else if (sharnging_if_plus == 0) {
    proverka_geni();
    if (gena <= SHARGING_ON) //еще раз смотрим что  зарядка пошла
    {
      actual_mode = 1; //Запоминаем что движок запущен
      razriv = 0;
      last_start_time = millis(); // запоминаем время запуска движка
      flash_count = 4 - left_start_try;
    }
    else
    {
      ENGINE_OUT_LOW();   //выключаем зажигание чтбы разблокировать реле стартера
      SECPOWER_OUT_LOW(); //выключаем печку фары итд
      delay(2000);
      if ( left_start_try > 0)
      {
        check_start();
      }
    }
  }
}

void check_for_shutdown()
{
  gena = 0;
  gena1 = 0;
  if (sharnging_else_plus == 1) {
    proverka_geni();
    if (gena <= SHARGING_ON  )
    {
      rucnik_OFF = 0;
      do_shutdown();
      delay(2000);
      check_start();
    }
    else
    {
      SECPOWER_OUT_HIGH();
      if (millis() > last_start_time + 3000) {
        if ((razriv == 0) && (ot_sms == 0) )
        {
          ne_zapusk1 = 0;
          zvonok();
          delay(200);
          razriv = 1;
          ne_zapusk = 1;
          set_time_call = millis();
        }
        else if ( (razriv == 0) && (ot_sms == 1))
        {
          proverka_pered_otpravkoi(); c = 0;
          while (c <= 3) {
            sms_esli_zavedena_uspeshno();
            proverka_modema();
          }
          razriv = 1;
        }
      }
    }
  }
  else if (sharnging_else_plus == 0) {
    proverka_geni();
    if (gena > SHARGING_ON  )
    {
      rucnik_OFF = 0;
      do_shutdown();
      delay(2000);
      check_start();
    }
    else
    {
      SECPOWER_OUT_HIGH();
      if (millis() > last_start_time + 3000) {
        if ((razriv == 0) && (ot_sms == 0) )
        {
          ne_zapusk1 = 0;
          zvonok();
          delay(200);
          razriv = 1;
          ne_zapusk = 1;
          set_time_call = millis();
        }
        else if ( (razriv == 0) && (ot_sms == 1))
        {
          proverka_pered_otpravkoi(); c = 0;
          while (c <= 3) {
            sms_esli_zavedena_uspeshno();
            proverka_modema();
          }
          razriv = 1;
        }
      }
    }
  }
  if (hand_brake_if_plus == 1) {
    if (analogRead(HAND_BRAKE_IN) > HAND_BRAKE_ON)
    {
      hand_brake_funkcion();
    }
  }
  else if (hand_brake_if_plus == 0) {
    if (analogRead(HAND_BRAKE_IN) <= HAND_BRAKE_ON)
    {
      hand_brake_funkcion();
    }
  }
  if (actual_mode != 0  )
  {
    if (millis() < last_start_time)
    {
      last_start_time = 0;
    }
    if (millis() > last_start_time + ENGINE_WARM_TIME)
    {
      POVOROT_OUT_LOW();
      SIRENA_LOW();
      rucnik_OFF = 0;
      do_shutdown();
      left_start_try = 0;
      proverka_pered_otpravkoi(); c = 0;
      while (c <= 3) {
        sms("progrev okonchen", MASTER_status);
        proverka_modema();
      }
    }
  }
}
void do_shutdown()
{
  SECPOWER_OUT_LOW(); //выключаем печку фары итд
  ENGINE_OUT_LOW(); //вырубаем зажигание
  actual_mode = 0;  // движок выключили запомним это
  zapusk_off = 0;
  last_start_time = 0; // ну и забудем о том что он был включен
  if (rucnik_OFF == 0)
  {
    POVOROT_OUT_LOW();
    rucnik_OFF = 1;
  }
}
void set_status_led()
{
  if (hand_brake_else_plus == 1) {
    if (analogRead(HAND_BRAKE_IN) <= HAND_BRAKE_ON  ) //Если ручник не стоит то выкл светодиод нечего ему в пути мигать попусту
    {
      STATUS_OUT_HIGH();
    }
    else
    {
      STATUS_OUT_LOW(); // постоянное свечение - показываем что готов к следующему запуску
    }
  }
  else if (hand_brake_else_plus == 0) {
    if (analogRead(HAND_BRAKE_IN) > HAND_BRAKE_ON  ) //Если ручник не стоит то выкл светодиод нечего ему в пути мигать попусту
    {
      STATUS_OUT_HIGH();
    }
    else
    {
      STATUS_OUT_LOW(); // постоянное свечение - показываем что готов к следующему запуску
    }
  }
  if (actual_mode ==  1) { //Движок запущен
    status_led_flash(); // показываем с какой попытки был прошлый запуск
    flag_set_status_led = 1;
  }
  if (actual_mode !=  1 && flag_set_status_led == 1)
  {
    POVOROT_OUT_LOW();
    STATUS_OUT_LOW();
    flag_set_status_led = 0;
  }
}
void status_led_flash()
{
  if (millis() > big_interval + 6000)
  {
    otmena_svecheniya = flash_count + 1;
  }
  if ((millis() > flash_interval + 500) && (otmena_svecheniya >= 1) && (vikluchil == 0))
  {
    vikluchil = 1;
    otmena_svecheniya--;
    POVOROT_OUT_HIGH();
    STATUS_OUT_HIGH();
    big_interval = millis();
    flash_interval = millis();
  }
  else if ((millis() > flash_interval + 500) && (otmena_svecheniya >= 0) && ( vikluchil == 1))
  {
    if ( otmena_svecheniya == 1)
    {
      otmena_svecheniya--;
    }
    vikluchil = 0;
    POVOROT_OUT_LOW();
    STATUS_OUT_LOW();
    big_interval = millis();
    flash_interval = millis();
  }
}
void sms_start_stop()
{
  if (val.indexOf("+CMT") > -1) {
    delay(200);
    if (((val.substring(1, 25)).indexOf(phone1.substring(1)) > -1) || ((val.substring(1, 25)).indexOf(phone2.substring(1)) > -1) || ((val.substring(1, 25)).indexOf(phone3.substring(1)) > -1) || (val.indexOf(PASSWORD) > -1)) {
      delay(200);
      if (val.indexOf(phone1.substring(1)) > -1) {
        delay(200);
        MASTER_status = phone1;
      }
      else if (val.indexOf(phone2.substring(1)) > -1)
      {
        delay(200);
        MASTER_status = phone2;
      }
      else if (val.indexOf(phone3.substring(1)) > -1)
      {
        delay(200);
        MASTER_status = phone3;
      }
      if ((val.indexOf(START_ON) > -1) && (actual_mode == 0 ) && (allow_start == 1)) {
        delay(200);
        left_start_try = 4;
        ot_sms = 1;
        razriv = 0;
        check_start();
      }
      else if ((val.indexOf(START_ON) > -1) && (actual_mode == 0 ) && (allow_start == 0))
      {
        proverka_pered_otpravkoi(); c = 0;
        while (c <= 3) {
          sms_zapusk_nevozmozhen();
          proverka_modema();
        }
      }
      else if ((val.indexOf(START_OFF) > -1) && (actual_mode != 0 ) && (allow_start == 1)) {
        rucnik_OFF = 0;
        do_shutdown();
        left_start_try = 0;
        last_start_time = 0;
        proverka_pered_otpravkoi(); c = 0;
        while (c <= 3) {
          sms_esli_zaglushen_uspeshno();
          proverka_modema();
        }
      }
      else if (val.indexOf(OPEN) > -1) {
        delay(200);
        open_button = 1;
      }
      else if (val.indexOf(CLOSED) > -1) {
        delay(200);
        close_button = 1;
      }
      else if (val.indexOf(TRUNK) > -1)
      {
        chanel_button = 1;
        Button_code = 0;
        otmena_povtora = 0;
      }
      else if (val.indexOf(SETUP) > -1)
      {
        prisvoenie_znacheniy();
      }
      else if (val.indexOf(RUCHNAYA) > -1)
      {
        ruchnaya_kpp = 1;
        EEPROM.update(46, ruchnaya_kpp);

        proverka_pered_otpravkoi();
        c = 0;
        while (c <= 3) {
          sms("ustanovlena ruchaya KPP", MASTER_status);
          proverka_modema();
        }
      }
      else if (val.indexOf(AVTOMAT) > -1)
      {
        ruchnaya_kpp = 0;
        EEPROM.update(46, ruchnaya_kpp);

        proverka_pered_otpravkoi();
        c = 0;
        while (c <= 3) {
          sms("ustanovlena avtomaticheskaya KPP", MASTER_status);
          proverka_modema();
        }
      }
      else if (val.indexOf(SIGNAL) > -1)
      {
        sirena_program = 1;
        EEPROM.update(47, sirena_program);

        proverka_pered_otpravkoi();
        c = 0;
        while (c <= 3) {
          sms("ustanovlen signal", MASTER_status);
          proverka_modema();
        }
      }
      else if (val.indexOf(SIRENA_ON) > -1)
      {
        sirena_program = 0;
        EEPROM.update(47, sirena_program);

        proverka_pered_otpravkoi();
        c = 0;
        while (c <= 3) {
          sms("ustanovlena sirena", MASTER_status);
          proverka_modema();
        }
      }

      if (val.indexOf(WRITE1) > -1)
      {
        zapis1 = 1;
      }
      else if (val.indexOf(WRITE2) > -1)
      {
        zapis1 = 2;
      }
      else if (val.indexOf(WRITE3) > -1)
      {
        zapis1 = 3;
      }
      if (val.indexOf(HARD_RESET) > -1)
      {
        hard_reset();
      }
      else if (val.indexOf(SBROS_NASTROEK) > -1)
      {
        minimal_reset();
      }
    }
    MY_GSM.println("AT+CMGD=1,4");
    delay(200);
  }
  else if (val.indexOf("+CLIP") > -1) {
    delay(200);
    sbros();
    if (((val.substring(1, 40)).indexOf(phone1.substring(1)) > -1) || ((val.substring(1, 40)).indexOf(phone2.substring(1)) > -1) || ((val.substring(1, 40)).indexOf(phone3.substring(1)) > -1)) {
      delay(200);
      if (val.indexOf(phone1.substring(1)) > -1) {
        delay(200);
        MASTER_status = phone1;
      }
      else if (val.indexOf(phone2.substring(1)) > -1)
      {
        delay(200);
        MASTER_status = phone2;
      }
      else if (val.indexOf(phone3.substring(1)) > -1)
      {
        delay(200);
        MASTER_status = phone3;
      }
      if ((actual_mode == 0 ) && (allow_start == 1)) {
        delay(200);
        left_start_try = 4;
        delay(200);
        ot_sms = 0;
        razriv = 0;
        check_start();
        delay(200);
      }
      else if ((actual_mode == 0 ) && (allow_start == 0))
      {
        proverka_pered_otpravkoi(); c = 0;
        while (c <= 3) {
          sms_zapusk_nevozmozhen();
          proverka_modema();
        }
      }
      else if ((actual_mode == 1 ) && (allow_start == 1)) {
        sbros();  //разрываем связь
        rucnik_OFF = 0;
        do_shutdown();
        left_start_try = 0; // и больше не заводим
        last_start_time = 0;
        delay(200);
        proverka_pered_otpravkoi(); c = 0;
        while (c <= 3) {
          sms_esli_zaglushen_uspeshno();
          proverka_modema();
        }
        delay(200);
      }
    }
  }
  if (zapis1 == 1)
  {
    phone1 = "";
    i = 4;
    while (((buf[i]) != '+') && i < 50)
    {
      delay(20);
      i++ ;
      l = 0;
      GO = 1;
    }
    while ((GO == 1) && (l < 12))
    {
      EEPROM.update(l, (buf[i]));
      delay(20);
      phone1 += buf[i];
      l++;
      i++;
    }
    GO = 0;
    zapis1 = 0;
    i = 0;
    delay(200);
    proverka_pered_otpravkoi();
    c = 0;
    while (c <= 3) {
      sms("nomer " + phone1 + " zapisan uspeshno", phone1);
      proverka_modema();
    }
    while (i < 131)
    {
      buf[i] = '\0';
      i++;
    }
    i = 0;
  }
  if (zapis1 == 2)
  {
    phone2 = "";
    i = 4;
    while (((buf[i]) != '+') && i < 50)
    {
      i++ ;
      l = 13;
      GO = 1;
    }
    while ((GO == 1) && (l < 25))
    {
      EEPROM.update(l, (buf[i]));
      delay(20);
      phone2 += buf[i];
      l++;
      i++;
    }
    i = 0;
    GO = 0;
    zapis1 = 0;
    delay(200);
    proverka_pered_otpravkoi(); c = 0;
    while (c <= 3) {
      sms("nomer " + phone2 + " zapisan uspeshno", phone2);
      proverka_modema();
    }
    while (i < 131)
    {
      buf[i] = '\0';
      i++;
    }
    i = 0;
  }
  if (zapis1 == 3)
  {
    phone3 = "";
    i = 4;
    while (((buf[i]) != '+') && i < 50)
    {
      i++ ;
      l = 26;
      GO = 1;
    }
    while ((GO == 1) && (l < 38))
    {
      EEPROM.update(l, (buf[i]));
      delay(20);
      phone3 += buf[i];
      l++;
      i++;
    }
    i = 0;
    GO = 0;
    zapis1 = 0;
    delay(200);
    proverka_pered_otpravkoi(); c = 0;
    while (c <= 3) {
      sms("nomer " + phone3 + " zapisan uspeshno", phone3);
      proverka_modema();
    }
    while (i < 131)
    {
      buf[i] = '\0';
      i++;
    }
    i = 0;
  }
  if ((val.indexOf("+CPAS: 1") > -1) || (val.indexOf("+CPAS: 2") > -1) || (val.indexOf("+CPAS: 5") > -1))
  {
    AT_CFUN_15();
    delay(200);
  }
  if  (val.indexOf("+PBREADY") > -1)
  {
    readi_modem();
  }
}
void drevi_off()
{
  if (millis() >= dlya_sekund_dveri + SRABOTKA_DVERI)
  {
    DOOR_CLOSE_LOW();
    DOOR_OPEN_LOW();
  }
}
void migaem_raz()
{
  if (flag_zakrit > 0) {
    if ((millis() >= dlya_miganiya + 500) && (flag_blink == 1)) {
      POVOROT_OUT_LOW();
      //SIRENA_LOW();
      dlya_miganiya = millis();
      flag_blink = 0;
      flag_zakrit--;
      rezreshil_proverku = 1;
    }
    else if ((millis() >= dlya_miganiya + 500) && (flag_blink == 0)) {
      POVOROT_OUT_HIGH();
      //vSIRENA_HIGH();
      dlya_miganiya = millis();
      flag_blink = 1;
      rezreshil_proverku = 0;
    }
  }
}
void sms(String text, String phone)  //процедура отправки СМС
{
  MY_GSM.println("AT+CMGS=\"" + phone + "\"");
  delay(300);
  MY_GSM.print(text);
  delay(300);
  MY_GSM.println((char)26);
  delay(400);
  //delay(2500);
}
void pinint()
{
  static uint32_t oldtime = micros();
  static uint8_t metka2 = 0;
  static byte metka = 0;
  if (digitalRead(RXD) == LOW)           //значит приняли ноль
  {
    oldtime = micros();                 //записали время
  }
  else
  {
    time = micros() - oldtime;             //нходим время в котором был 0 или 1
    // Serial.println(time);
    if (constrain(time, 13400 - DELTA1, 13400 + DELTA1) == time)// если попадает 0 или еденица в интервал от 10000 до 16800 значит пришел стартовы бит и начнем считать саму посылку
    {
      metka = 1;                                              //выставилм метки что бы понять что посылка кода пошла
      metka2 = 0;                                              //выставилм метки что бы понять что посылка кода пошла
      code = 0;
      rcvd_err = 0; //сброс флага ошибки
      received = 0; //сброс флага приема
    }
    if (metka == 1 && metka2 <= 24 )                            //значит метки совпадают начинаем читать сигналы
    {
      metka2++;                                                  //выставим что бы метка отсчитала 24 посылки "1" и "0", после 24 приходит мусор
      code <<= 1; //заполняем, как обойму в АК, проталкивая старое влево. Последние принятые разряды окажуться младшими
      if (constrain(time, 1300 - DELTA, 1300 + DELTA) == time)   //если пришла 1 запишем ее в функцию, там она напечатается в монитор
      {
        code |= 1UL;
      }
      else if (constrain(time, 51, 799) == time)                  //если пришел 0 запишем его в функцию, там он напечатается в монитор
      {
        code &= ~1UL;
      }
      else if (constrain(time, 0, 50) == time)                   // если поймапли какой то мусор, сразу обрубаем чтение порта
      {
        metka = 0;
        metka2 = 25;
        rcvd_err = 1;
      }
      if ( metka2 == 25)                                           //ну это для образовательных целей что бы видеть разрыв между посылками
      {
        received = 1;
      }
    }
  }
}
void kakaya_knopka()
{
  if (received) {
    if (! rcvd_err) //если нет ошибки напечатаем отдельно код брелока и кнопки.
    {
      RC_code = code >> 4;
      Button_code = code & 0xf;
      //Serial.println(RC_code);
      //Serial.println(Button_code);
    }
    received = 0; // обработав, снимаем флаг
    if ((RC_code == KOD_BRELKA) || (RC_code == KOD_BRELKA1))
    {
      RC_code = 0;
      if (Button_code == KOD_KNOPKI_CLOSED) {
        close_button = 1;
        Button_code = 0;
      }
      else if (Button_code == KOD_KNOPKI_OPEN)
      {
        open_button = 1;
        Button_code = 0;
      }
      else if (Button_code == KOD_KNOPKI_CHANEL)
      {
        chanel_button = 1;
        Button_code = 0;
        otmena_povtora = 0;
      }
      else if (Button_code == KOD_KNOPKI_ZAPUSK)
      {
        Button_code = 0;
        zapusk_button = 1;
      }
    }
  }
  Button_code = 0;
  RC_code = 0;
}
void button()
{
  if (close_button == 1)
  {
    DOP_RELEY_LOW();
    DOOR_CLOSE_HIGH();
    DOOR_OPEN_LOW();
    dlya_sekund_dveri = millis();
    close_button = 0;
    open_button = 0;
    chanel_button = 0;
    dlya_miganiya = millis();
    if (analogRead(KONCEVIKI) > 300)
    {
      flag_security_konceviki = 0;
      securiti = 1;
    }
    else if (analogRead(KONCEVIKI) <= 300)
    {
      proverka_pered_otpravkoi(); c = 0;
      while (c <= 3) {
        sms("WARRING!!! dveri libo kapot otrity", MASTER_status);
        proverka_modema();
      }
      delay(200);
      SIRENA_HIGH();
      POVOROT_OUT_HIGH();
      delay(200);
      SIRENA_LOW();
      delay(300);
      POVOROT_OUT_LOW();
      delay(500);
      SIRENA_HIGH();
      POVOROT_OUT_HIGH();
      delay(200);
      SIRENA_LOW();
      delay(300);
      POVOROT_OUT_LOW();
      delay(500);
      SIRENA_HIGH();
      POVOROT_OUT_HIGH();
      delay(200);
      SIRENA_LOW();
      delay(300);
      POVOROT_OUT_LOW();
      delay(500);
    }
    POVOROT_OUT_HIGH();
    SIRENA_HIGH();
    delay(100);
    SIRENA_LOW();
    delay(200);
    SIRENA_HIGH();
    delay(100);
    SIRENA_LOW();
    flag_zakrit = 2; flag_blink = 1;
    rezreshil_proverku = 0;
    millis_dor_close = millis();
  }
  else if (open_button == 1)
  {
    DOP_RELEY_HIGH();
    log_netral_gotov = 0;
    DOOR_OPEN_HIGH();
    dlya_sekund_dveri = millis();
    DOOR_CLOSE_LOW();
    close_button = 0;
    open_button = 0;
    chanel_button = 0;
    dlya_miganiya = millis();
    POVOROT_OUT_HIGH();

    SIRENA_HIGH();
    delay(100);
    SIRENA_LOW();
    delay(200);
    rezreshil_proverku = 0;
    flag_zakrit = 1; flag_blink = 1;
    securiti = 0;
    flag_security_konceviki = 1;
    warring_security = 0;
    flag_raz_sirena = 0;
    //SIRENA_LOW();
    flag_sirena_high = 0;
    flag_dva_sirena = 3;
    sbros();
    delay(500);
  }
  else if (chanel_button == 1 || otmena_povtora < 1)
  {
    BAGAZHNIK_OUT_HIGH();
    delay(100);
    BAGAZHNIK_OUT_LOW();
    delay(50);
    otmena_povtora ++;
    close_button = 0;
    open_button = 0;
    chanel_button = 0;
  }
  else if (zapusk_button == 1)
  {
    zapusk_button = 0;
    if ((actual_mode == 0 ) && (allow_start == 1)) {
      delay(200);
      left_start_try = 4;
      delay(200);
      ot_sms = 0;
      razriv = 0;
      check_start();
      delay(200);
    }
    else if ((actual_mode == 0 ) && (allow_start == 0))
    {
      proverka_pered_otpravkoi(); c = 0;
      while (c <= 3)
      {
        sms_zapusk_nevozmozhen();
        proverka_modema();
      }
    }
  }
}
void proverka_skoroti()
{
  if (ruchnaya_kpp == 0)
  {
    gena = 0;
    gena1 = 0;
    if (sharnging_if_plus == 1) {
      proverka_geni();
      if (gena > SHARGING_ON)
      {
        proverka_skorosty1 = 1;
      }
    }
    else if (sharnging_if_plus == 0) {
      proverka_geni();
      if (gena <= SHARGING_ON)
      {
        proverka_skorosty1 = 1;
      }
    }
    if (hand_brake_if_plus == 1 && (proverka_skorosty1 == 1)) {
      if (sharnging_else_plus == 1) {
        proverka_geni();
        if (   (gena <= SHARGING_ON) && (analogRead(HAND_BRAKE_IN) > HAND_BRAKE_ON )) {
          otmetka_skorosty = 1;
          proverka_skorosty1 = 0;
        }
      }
      else if (sharnging_else_plus == 0) {
        proverka_geni();
        if (gena > SHARGING_ON && (analogRead(HAND_BRAKE_IN) > HAND_BRAKE_ON )) {
          otmetka_skorosty = 1;
          proverka_skorosty1 = 0;
        }
      }
    }
    else if (hand_brake_if_plus == 0 && (proverka_skorosty1 == 1)) {
      if (sharnging_else_plus == 1) {
        proverka_geni();
        if ( gena <= SHARGING_ON && (analogRead(HAND_BRAKE_IN) <= HAND_BRAKE_ON )) {
          otmetka_skorosty = 1;
          proverka_skorosty1 = 0;
        }
      }
      else if (sharnging_else_plus == 0) {
        proverka_geni();
        if ( gena > SHARGING_ON && (analogRead(HAND_BRAKE_IN) <= HAND_BRAKE_ON )) {
          otmetka_skorosty = 1;
          proverka_skorosty1 = 0;
        }
      }
    }
    if (  otmetka_skorosty == 1)
    {
      flag_raz = 1;
      proverka_skorosty1 = 0;
      otmetka_skorosty = 0;
      sekunda_skoroty = millis();
      flag_dva = 0;
    }
    if ((actual_mode == 0) && (flag_dva < 3))
    {
      //  1");
      if (hand_brake_else_plus == 1) {
        if (sharnging_if_plus == 1) {
          proverka_geni();
          if (millis() >= sekunda_skoroty + 10000 || analogRead(HAND_BRAKE_IN)  <= HAND_BRAKE_ON || gena > SHARGING_ON ) {

            POVOROT_OUT_LOW();
            otmetka_skorosty = 0;
            flag_raz = 0;
            flag_dva = 3;

          }
        }
        else  if (sharnging_if_plus == 0) {
          proverka_geni();
          if (millis() >= sekunda_skoroty + 10000 || analogRead(HAND_BRAKE_IN) <= HAND_BRAKE_ON || gena <= SHARGING_ON ) {

            POVOROT_OUT_LOW();
            otmetka_skorosty = 0;
            flag_raz = 0;
            flag_dva = 3;

          }
        }
      }
      else if (hand_brake_else_plus == 0) {
        if (sharnging_if_plus == 1) {
          proverka_geni();
          if (millis() >= sekunda_skoroty + 10000 || analogRead(HAND_BRAKE_IN) > HAND_BRAKE_ON || gena > SHARGING_ON ) {
            POVOROT_OUT_LOW();
            otmetka_skorosty = 0;
            flag_raz = 0;
            flag_dva = 3;
          }
        }
        else  if (sharnging_if_plus == 0) {
          proverka_geni();
          if (millis() >= sekunda_skoroty + 10000 || analogRead(HAND_BRAKE_IN) > HAND_BRAKE_ON || gena <= SHARGING_ON ) {
            POVOROT_OUT_LOW();
            // 2");
            otmetka_skorosty = 0;
            flag_raz = 0;
            flag_dva = 3;
          }
        }
      }
    }
  }
}
void Miganie()
{
  if (flag_dva == 0 && millis() >= sekunda_skoroty + (300 * flag_raz))
  {
    POVOROT_OUT_HIGH();
    flag_raz++;
    flag_dva = 1;
  }
  else if (flag_dva == 1 && millis() >= sekunda_skoroty + (300 * flag_raz)) {
    POVOROT_OUT_LOW();
    flag_raz++;
    flag_dva = 0;
  }
  if (flag_dva == 3 && sbros_miganiya == 1)
  {
    flag_raz = 0;
    sbros_miganiya = 0;
    POVOROT_OUT_LOW();
  }
}

//функция чтения настроек из ЕЕПРОМ
void eprom_read()
{
  i = 0;
  phone1 = "";
  while (i < 12)
  {
    data = EEPROM.read(i);
    delay(20);
    phone1 += data;
    i++;
  }
  if (phone1.indexOf("+7") > -1)
  {
    phone1 = phone1;
  }
  else
  {
    phone1 = ("+71111111111");
  }
  phone2 = "";
  i = 13;
  while (i < 25)
  {
    data = EEPROM.read(i);
    delay(20);
    phone2 += data;
    i++;
  }
  if (phone2.indexOf("+7") > -1)
  {
    phone2 = phone2;
  }
  else
  {
    phone2 = ("+71111111111");
  }
  i = 26;
  phone3 = "";
  while (i < 38)
  {
    data = EEPROM.read(i);
    delay(20);
    phone3 += data;
    i++;
  }
  if (phone3.indexOf("+7") > -1)
  {
    phone3 = phone3;
  }
  else
  {
    phone3 = ("+71111111111");
  }
  EEPROM.get(50, SHARGING_ON);
  delay(20);
  EEPROM.get(70, HAND_BRAKE_ON);
  delay(20);
  sharnging_if_plus = EEPROM.read(40);
  delay(5);
  sharnging_else_plus = EEPROM.read(41);
  delay(5);
  hand_brake_if_plus = EEPROM.read(42);
  delay(5);
  hand_brake_else_plus = EEPROM.read(43);
  delay(5);
  allow_start = EEPROM.read(44);
  delay(5);
  ruchnaya_kpp = EEPROM.read(46);
  delay(5);
  sirena_program = EEPROM.read(47);
  delay(5);
}
void prisvoenie_znacheniy()
{
  gena1 = 0;
  gena = 0;
  ENGINE_OUT_HIGH();//включаем зажигание
  delay(500);
  proverka_geni();
  generator_nashalo = gena;      //если значение генератора правельные, записываем их в переменную как начальные
  ruchik_nachalo = analogRead(HAND_BRAKE_IN);   //и считываем начальные значения положения рычага КПП(ручника)
  proverka_pered_otpravkoi(); c = 0;
  while (c <= 3) {
    sms("snimite skorost', potom zavedite avto", MASTER_status); //отсылаем смс с дальнейшими действиями
    proverka_modema();
  }
  delay(200);
  h = 0;
  while ( h <= 12000)
  {
    proverka_geni();
    generator_seredina = gena; //если значение генератора правельные, записываем их в переменную для вычеслений из начального в средние
    ruchik_seredina = analogRead(HAND_BRAKE_IN); //то же с ручником или рычагом КПП
    h++;
    if (((generator_nashalo + 50) <= generator_seredina) || ((generator_nashalo - 50) >= generator_seredina))// посмотрели машина завилась
    {
      delay(2000);
      proverka_geni();
      generator_seredina = gena; //записываем уже конечные значения
      ruchik_seredina = analogRead(HAND_BRAKE_IN); //записываем уже конечные значения
      otmetka1 = 2;
      break;
    }
  }
  if ((h <= 11999) && (otmetka1 == 2)) {
    generator_konec = ((generator_nashalo + generator_seredina) / 2); //находим среднее значение между заглушенный и заведенной машиной
    delay(20);
    ruchik_konec = ((ruchik_nachalo + ruchik_seredina) / 2);//находим среднее значение между заглушенный и заведенной машиной
    delay(20);
    SHARGING_ON = generator_konec;
    HAND_BRAKE_ON = ruchik_konec;
    EEPROM.put(50, SHARGING_ON); //записываем их в EEPROM
    delay(5);
    EEPROM.put(70, HAND_BRAKE_ON);//записываем их в EEPROM
    delay(5);
    otmetka1 = 1;
    // дальше смотрим что бы у нас выполнялись правильные куски программы
    // потому что переменная генератора может и увеличиться с запуском двигателя
    // так и уменьшиться, мы как раз здесь это и смотрим
    // и записываем все в ЕЕПРОМ
    if (generator_nashalo < generator_seredina)
    {
      sharnging_if_plus = 1;
      sharnging_else_plus = 1;
      EEPROM.update(40, sharnging_if_plus);
      delay(5);
      EEPROM.update(41, sharnging_else_plus);
      delay(5);
      otmetka2 = 1;
    }
    else if (generator_nashalo > generator_seredina)
    {
      sharnging_if_plus = 0;
      sharnging_else_plus = 0;
      EEPROM.update(40, sharnging_if_plus);
      delay(5);
      EEPROM.update(41, sharnging_else_plus);
      delay(5);
      otmetka2 = 1;
    }
    // то же самое и с ручником
    if (ruchik_nachalo < ruchik_seredina)
    {
      hand_brake_if_plus = 0;
      hand_brake_else_plus = 0;
      EEPROM.update(42, hand_brake_if_plus);
      delay(5);
      EEPROM.update(43, hand_brake_else_plus);
      delay(5);
      otmetka3 = 1;
    }
    else if (ruchik_nachalo > ruchik_seredina)
    {
      hand_brake_if_plus = 1;
      hand_brake_else_plus = 1;
      EEPROM.update(42, hand_brake_if_plus);
      delay(5);
      EEPROM.update(43, hand_brake_else_plus);
      delay(5);
      otmetka3 = 1;
    }
    //если мы прошли все отметки с успехом, то отправляем смс с такой командой
    if (otmetka1 == 1 && otmetka2 == 1 && otmetka3 == 1)
    {
      proverka_pered_otpravkoi(); c = 0;
      while (c <= 3) {
        sms("ustanovki sohraneni uspeshno", MASTER_status);
        proverka_modema();
      }
      ENGINE_OUT_LOW();
      otmetka1 = 0;
      otmetka2 = 0;
      otmetka2 = 0;
      allow_start = 1;
      EEPROM.update(44, allow_start);
    }
  }
  // если закончилось время и мы не завели авто то шлем смс с ошибкой
  else if (h > 11999)
  {
    allow_start = 0;
    EEPROM.update(44, allow_start);
    ENGINE_OUT_LOW();

  }
  //или если какую то отметку не прошли тоже смс с ошибкой
  else if (otmetka1 == 0 || otmetka2 == 0 || otmetka3 == 0)
  {
    allow_start = 0;
    EEPROM.update(44, allow_start);
    otmetka1 = 0;
    otmetka2 = 0;
    otmetka2 = 0;
    ENGINE_OUT_LOW();

  }
}
void proverka_securiti()
{
  if ((analogRead(KONCEVIKI) <= 300) && flag_security_konceviki == 0)
  {
    flag_security_konceviki = 1;
    delay(200);
    proverka_pered_otpravkoi(); c = 0;

    while (c <= 3) {
      sms("srabotala signalizaciya", MASTER_status);
      proverka_modema();
    }
    delay(200);
    zvonok();
    delay(200);
    flag_securiti_1 = 1;
    warring_security = 1;
    set_time_call = millis();
    left_start_try = 4;
    ot_sms = 1;
    razriv = 0;
    check_start();
    if (sirena_program == 0)
    {

      SIRENA_HIGH();
    }
    else if (sirena_program == 1)
    {
      flag_raz_sirena = 1;
      sekunda_skoroty_sirena = millis();
      flag_dva_sirena = 0;
      srabotka_koncevikov = 1;
    }
  }
  if ((zapusk_off == 0) && (digitalRead(DOOR_CLOSE) == 0))
  {
    if (millis > millis_dor_close + 3000) {
      if ((analogRead(SHOCK_SENSOR_HIGH) <= 300) && (flag_sirena_high == 0))
      {

        if (sirena_program == 0)
        {
          SIRENA_HIGH();
          flag_sirena_high = 1;
          delay_millis_sirena_high = millis();
          flag_sirena_millis = 0;
        }
        else if (sirena_program == 1)
        {
          flag_raz_sirena = 1;
          sekunda_skoroty_sirena = millis();
          delay_millis_sirena_high = millis();
          flag_dva_sirena = 0;
          srabotka_koncevikov = 0;
          flag_sirena_millis = 0;
        }
        proverka_pered_otpravkoi(); c = 0;
        while (c <= 3) {
          sms("mashinu udarili", MASTER_status);
          proverka_modema();
        }
      }
      if (analogRead(SHOCK_SENSOR_LOW) <= 300)
      {
        SIRENA_HIGH();
        delay (400);
        SIRENA_LOW();
        delay (700);
        SIRENA_HIGH();
        delay (400);
        SIRENA_LOW();
        delay (700);
        SIRENA_HIGH();
        delay (400);
        SIRENA_LOW();
      }
      if (flag_sirena_millis == 0) {
        if (millis() > (delay_millis_sirena_high + 120000))
        {
          SIRENA_LOW();
          flag_sirena_high = 0;
          flag_sirena_millis = 1;
        }
      }
    }
  }
}
void sirena_prerivanie()
{

  if (flag_dva_sirena == 0 && millis() >= sekunda_skoroty_sirena + (800 * flag_raz_sirena))
  {
    SIRENA_HIGH();
    flag_raz_sirena++;
    flag_dva_sirena = 1;
  }
  else if (flag_dva_sirena == 1 && millis() >= sekunda_skoroty_sirena + (800 * flag_raz_sirena)) {
    SIRENA_LOW();
    flag_raz_sirena++;
    flag_dva_sirena = 0;
  }
  if (srabotka_koncevikov == 0) {
    if (flag_dva_sirena == 3 || (millis() > (delay_millis_sirena_high + 120000)))
    {
      flag_raz_sirena = 0;
      SIRENA_LOW();
      flag_sirena_high = 0;
      flag_dva_sirena = 3;
    }
  }


}
void proverka_geni()
{
  gena = analogRead(SHARGING_IN);
  delay(5);
  gena1 = analogRead(SHARGING_IN);
  for (; gena1 != gena;)
  {
    gena = analogRead(SHARGING_IN);
    delay(5);
    gena1 = analogRead(SHARGING_IN);
  }
}

void reset_modem()
{
  if (reset_modem_millis > millis())
  {
    reset_modem_millis = 0;
  }
  if (millis() > reset_modem_millis + 120000)
  {
    reset_modem_millis = millis();
    proverka_reset = 1;
  }
  if ( proverka_reset == 1)
  {
    reset_proverki_modema();
    modem_v_gsm();
    MY_GSM.println("AT+CPAS");
    proverka_reset = 0;
  }
}
void hard_reset()
{
  for (int i = 0 ; i < EEPROM.length() ; i++) {
    EEPROM.write(i, 0);
  }
  minimal_reset();
}
void minimal_reset()
{
  flag_sirena_high = 0;
  SHARGING_ON = 0;
  HAND_BRAKE_ON = 0;
  h = 0;
  ne_zapusk1 = 5;
  flag_set_status_led = 1;
  sharnging_if_plus = 1;
  sharnging_else_plus = 1;
  hand_brake_if_plus = 1;
  hand_brake_else_plus = 1; gena = 0;
  gena1 = 0;
  otmetka1 = 0;
  otmetka2 = 0;
  otmetka3 = 0;
  zapusk_button = 0;
  rucnik_OFF = 1;
  GO = 0;
  proverka_skorosty1 = 0;
  zapis1 = 0;
  otmetka_skorosty = 0;
  razriv = 0;
  chanel_button = 0;
  open_button = 0;
  close_button = 0;
  securiti = 0;
  flag_security_konceviki = 1;
  flag_securiti = 0;
  actual_mode = 0; //  2 engine started
  allow_start = 0;
  ot_sms = 0;
  warring_security = 0;
  flag_securiti_1 = 0;
  flag_blink = 1;
  proverka_reset = 0;
  flag_zakrit = 0;
  c = 0;
  flash_count = 0;
  dlya_ruchnika = 0;
  left_start_try = 0;  // переменная для хранения остатка числа попыток запуска
  ch = 0; //
  otmena_povtora = 10;
  flag_raz = 0;
  ne_zapusk = 0;
  generator_nashalo = 0;
  generator_seredina = 0;
  generator_konec = 0;
  ruchik_nachalo = 0;
  ruchik_seredina = 0;
  ruchik_konec = 0;
  MASTER_status = "";
  big_interval = 0;
  flash_interval = 0;
  last_start_time = 0; //время в тысячных секунды когда был запущен движок
  sekunda_skoroty = 0;
  set_time_call = 0;
  dlya_sekund_dveri = 0; // для хранения секнд сработки дверей
  dlya_miganiya = 0;
  reset_modem_millis = 0;
  flag_dva = 3;
  rcvd_err = 0; //флаг наличия ошибки приема
  obnulenie = 1;
  data = 0;
  millis_dor_close = 0;
  phone1 = "+71111111111";
  phone2 = "+71111111111";
  phone3 = "+71111111111";
  otmena_svecheniya = 0;
  vikluchil = 0;
  delay_millis_sirena_high = 0;
  zapusk_off = 0;
  nastroyki();
}
void nastroyki()
{
  SIRENA_LOW();
  STARTER_OUT_LOW();
  ENGINE_OUT_LOW();
  SECPOWER_OUT_LOW();
  STATUS_OUT_LOW();
  BAGAZHNIK_OUT_LOW();
  DOOR_OPEN_LOW();
  DOOR_CLOSE_LOW();
  digitalWrite(14, HIGH);
  digitalWrite(15, HIGH);
  digitalWrite(16, HIGH);
  digitalWrite(17, HIGH);
  digitalWrite(18, HIGH);
  digitalWrite(19, HIGH);
  DOP_RELEY_HIGH();
  pinMode(RXD, INPUT);
  attachInterrupt(digitalPinToInterrupt(RXD), pinint, CHANGE);
  delay(100);
  Serial.begin(460800);
  MY_GSM.begin(460800);
  AT_IPR_9600();
  delay(200);
  Serial.begin(230400);
  MY_GSM.begin(230400);
  AT_IPR_9600();
  delay(200);
  Serial.begin(115200);
  MY_GSM.begin(115200);
  AT_IPR_9600();
  delay(200);
  Serial.begin(57600);
  MY_GSM.begin(57600);
  AT_IPR_9600();
  delay(200);
  Serial.begin(38400);
  MY_GSM.begin(38400);
  AT_IPR_9600();
  delay(200);
  Serial.begin(28800);
  MY_GSM.begin(28800);
  AT_IPR_9600();
  Serial.begin(19200);
  MY_GSM.begin(19200);
  AT_IPR_9600();
  delay(200);
  Serial.begin(14400);
  MY_GSM.begin(14400);
  AT_IPR_9600();
  delay(200);
  Serial.begin(4800);
  MY_GSM.begin(4800);
  AT_IPR_9600();
  delay(200);
  Serial.begin(2400);
  MY_GSM.begin(2400);
  AT_IPR_9600();
  delay(200);
  Serial.begin(9600);
  MY_GSM.begin(9600);
  delay(100);
  eprom_read();
  MASTER_status = phone1;

  POVOROT_OUT_LOW();
  // Serial.println(ruchnaya_kpp);
}
void log_netral()
{
  if (hand_brake_if_plus == 1) {
    if ((analogRead(HAND_BRAKE_IN) < HAND_BRAKE_ON) && (otschet_poshel == 0))
    {
      if (sharnging_if_plus == 1)
      {
        proverka_geni();
        if (gena > SHARGING_ON)
        {
          SIRENA_HIGH();
          delay(200);
          SIRENA_LOW();
          otschet_poshel = 1;
          otschet_neitrali = millis();
          ENGINE_OUT_HIGH();
          sekunda_skoroty = millis();
          flag_raz = 1;
          flag_dva = 0;
          sbros_miganiya = 1;

        }
      }
      else if (sharnging_if_plus == 0)
      {
        proverka_geni();
        if (gena < SHARGING_ON)
        {
          SIRENA_HIGH();
          delay(200);
          SIRENA_LOW();
          otschet_poshel = 1;
          otschet_neitrali = millis();
          ENGINE_OUT_HIGH();
          sekunda_skoroty = millis();
          flag_raz = 1;
          flag_dva = 0;
          sbros_miganiya = 1;
        }
      }
    }
    else if (analogRead(HAND_BRAKE_IN) > HAND_BRAKE_ON)
    {
      otschet_neitrali = millis();
      flag_dva = 3;
      otschet_poshel = 0;
      ENGINE_OUT_LOW();
      log_netral_gotov = 0;
    }
  }
  if (hand_brake_if_plus == 0) {
    if ((analogRead(HAND_BRAKE_IN) > HAND_BRAKE_ON) && (otschet_poshel == 0))
    {
      if (sharnging_if_plus == 1)
      {
        proverka_geni();
        if (gena > SHARGING_ON)
        {
          SIRENA_HIGH();
          delay(200);
          SIRENA_LOW();
          otschet_poshel = 1;
          otschet_neitrali = millis();
          ENGINE_OUT_HIGH();
          sekunda_skoroty = millis();
          flag_raz = 1;
          flag_dva = 0;
          sbros_miganiya = 1;

        }
      }
      else if (sharnging_if_plus == 0)
      {
        proverka_geni();
        if (gena < SHARGING_ON)
        {
          SIRENA_HIGH();
          delay(200);
          SIRENA_LOW();
          otschet_poshel = 1;
          otschet_neitrali = millis();
          ENGINE_OUT_HIGH();
          sekunda_skoroty = millis();
          flag_raz = 1;
          flag_dva = 0;
          sbros_miganiya = 1;
        }
      }
    }
    else if (analogRead(HAND_BRAKE_IN) < HAND_BRAKE_ON)
    {
      otschet_neitrali = millis();
      flag_dva = 3;
      otschet_poshel = 0;
      ENGINE_OUT_LOW();
      log_netral_gotov = 0;
    }
  }
  if ((otschet_poshel == 1) && (millis() < (otschet_neitrali + ZADERZHKA_LOG_NETRAL)))
  {
    if (analogRead(KONCEVIKI) < 500)
    {
      dveri_otkrili = 1;
    }
    if ((dveri_otkrili == 1) && (securiti == 1) && (analogRead(KONCEVIKI) > 500))
    {
      log_netral_gotov = 1;
      flag_dva = 3;
      ENGINE_OUT_LOW();
    }
  }
  if ((otschet_poshel == 0) || (millis() > (otschet_neitrali + ZADERZHKA_LOG_NETRAL)))
  {
    flag_dva = 3;
    ENGINE_OUT_LOW();
  }
  if ((otschet_poshel == 0) || (millis() > (otschet_neitrali + 2000)))
  {
    flag_dva = 3;
  }
}
void zvonok()
{
  MY_GSM.println("ATD" + MASTER_status + ";");
}
void sbros()
{
  MY_GSM.println("ATH0");
}
void POVOROT_OUT_LOW()
{
  digitalWrite(POVOROT_OUT, LOW);
}
void STATUS_OUT_LOW()
{
  digitalWrite(STATUS_OUT, LOW);
}
void SIRENA_LOW()
{
  digitalWrite(SIRENA, LOW);
}
void STARTER_OUT_LOW()
{
  digitalWrite(STARTER_OUT, LOW);
}
void ENGINE_OUT_LOW()
{
  digitalWrite(ENGINE_OUT, LOW);
}
void SECPOWER_OUT_LOW()
{
  digitalWrite(SECPOWER_OUT, LOW);
}
void BAGAZHNIK_OUT_LOW()
{
  digitalWrite(BAGAZHNIK_OUT, LOW);
}
void DOOR_OPEN_LOW()
{
  digitalWrite(DOOR_OPEN, LOW);
}
void DOOR_CLOSE_LOW()
{
  digitalWrite(DOOR_CLOSE, LOW);
}
void ENGINE_OUT_HIGH()
{
  digitalWrite(ENGINE_OUT, HIGH);
}
void STARTER_OUT_HIGH()
{
  digitalWrite(STARTER_OUT, HIGH);
}
void  SECPOWER_OUT_HIGH()
{
  digitalWrite(SECPOWER_OUT, HIGH);
}
void STATUS_OUT_HIGH()
{
  digitalWrite(STATUS_OUT, HIGH);
}
void POVOROT_OUT_HIGH()
{
  digitalWrite(POVOROT_OUT, HIGH);
}
void DOOR_CLOSE_HIGH()
{
  digitalWrite(DOOR_CLOSE, HIGH);
}
void SIRENA_HIGH()
{
  digitalWrite(SIRENA, HIGH);
}
void DOOR_OPEN_HIGH()
{
  digitalWrite(DOOR_OPEN, HIGH);
}
void BAGAZHNIK_OUT_HIGH()
{
  digitalWrite(BAGAZHNIK_OUT, HIGH);
}
void DOP_RELEY_HIGH()
{
  digitalWrite(DOP_RELEY, HIGH);
}
void DOP_RELEY_LOW()
{
  digitalWrite(DOP_RELEY, LOW);
}
void AT_IPR_9600()
{
  MY_GSM.println("AT+IPR=9600");
}
void AT_CFUN_15()
{
  MY_GSM.println("AT+CFUN=15");
}
void readi_modem()
{
  delay(100);
  MY_GSM.println("AT+CLIP=1");        //включаем АОН
  delay(100);
  MY_GSM.println("AT+CMGF=1");        //режим кодировки СМС - обычный (для англ.)
  delay(100);
  MY_GSM.println("AT+CSCS=\"GSM\"");  //режим кодировки текста
  delay(100);
  MY_GSM.println("AT+CNMI=2,2");      //отображение смс в терминале сразу после приема (без этого сообщения молча падают в память)
  delay(100);
  MY_GSM.println("ATE1");
}
void proverka_pered_otpravkoi()
{
  if (proverka_pered_otpravkoi_1 < 20)
  {
    MY_GSM.println("AT+CSQ");
    delay(200);
    val = "";
    while (MY_GSM.available())
    {
      ch = MY_GSM.read();
      delay(10);
      val += ch;
    }
    Serial.println(val);

    if  (val.indexOf("99") > -1)
    {
      delay(500);
      proverka_pered_otpravkoi_1++;
      val = "";
      proverka_pered_otpravkoi();

    }
  }
  val = "";
  proverka_pered_otpravkoi_1 = 0;
}
void reset_proverki_modema()
{
  val = "";
  MY_GSM.println("AT");
  delay(400);
  if (MY_GSM.available() )   {     //есть данные от GSM модуля
    i = 0;
    while (i < 131)
    { buf[i] = '\0';
      i++;
    }

    i = 0;
    while (MY_GSM.available()) {
      ch = MY_GSM.read();
      delay(10);
      buf[i] = ch;
      val += ch;
      i++;
    }
    buf[i] = '\0';
    Serial.println(val);
  }
  if (val.indexOf("OK") > -1)
  {
    return;
  }
  else
  {
    AT_CFUN_15();
    delay(200);
  }
}
void modem_v_gsm()
{
  val = "";
  MY_GSM.println("AT+CSCS=?");
  delay(400);
  if (MY_GSM.available() )   {     //есть данные от GSM модуля
    i = 0;
    while (i < 131)
    { buf[i] = '\0';
      i++;
    }

    i = 0;
    while (MY_GSM.available()) {
      ch = MY_GSM.read();
      delay(10);
      buf[i] = ch;
      val += ch;
      i++;
    }
    buf[i] = '\0';
    Serial.println(val);
  }
  if (val.indexOf("GSM") > -1)
  {
    return;
  }
  else
  {
    readi_modem();
    delay(200);
  }
}

 

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

У Вас полно статичных строк может сначала от них избавиться с помощью F или прогмем, а там видно будет

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

Penni пишет:
У Вас полно статичных строк может сначала от них избавиться с помощью F или прогмем, а там видно будет

не понимаю о чем вы сможете ссылку привести где можно почитать об "F"

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

понял на счет F, супер, ноо большой ущерб памяти флеш... у меня и так флеша 76% на 328p-au

 

arduinec
Offline
Зарегистрирован: 01.09.2015

d13lider пишет:

не понимаю о чем вы сможете ссылку привести где можно почитать об "F"

http://atmel.ucoz.ru/publ/progmem/1-1-0-64

b707
Offline
Зарегистрирован: 26.05.2017

d13lider пишет:

понял на счет F, супер, ноо большой ущерб памяти флеш... у меня и так флеша 76% на 328p-au

флеш можно использовать хоть на 100% - лишь бы хватило. А вот оперативку нежелательно забивать более 60-70% - иначе могут начаться глюки.

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

на счет F просто супер))) все работает!! спасибо большое! и теперь освободил с 74% до 42% отлично вообще!

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

да, все таки полезно скетч выкладывать... думал будет бесполезный

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

может еще элементарные способы оптимизации подскажите? на ваш взгляд

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

жесть... уже до 38% снизил... вот это я косяяяяяяяяяяк

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

наверное я такой криворукий, но у меня весь скетч на char[] и тоже занимает более 80 % динамической памяти,

250 байт входящий буфер от модема, 250 байт исходящий буфер для отправки SMS в PDU формате,

и даже учитывая что я максимально многократно стараюсь использовать одни и те же переменные,

и без этих двух буферов все равно много памяти съедается :(

не знаю как на УНО умудряются мегапроекты строить....

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

andycat пишет:

наверное я такой криворукий, но у меня весь скетч на char[] и тоже занимает более 80 % динамической памяти,

250 байт входящий буфер от модема, 250 байт исходящий буфер для отправки SMS в PDU формате,

и даже учитывая что я максимально многократно стараюсь использовать одни и те же переменные,

и без этих двух буферов все равно много памяти съедается :(

не знаю как на УНО умудряются мегапроекты строить....

80% это на каком чипе?

 

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

328 чип

Скетч использует 19380 байт (60%) памяти устройства. Всего доступно 32256 байт.
Глобальные переменные используют 1641 байт (80%) динамической памяти, оставляя 407 байт для локальных переменных. Максимум: 2048 байт.
Недостаточно памяти, программа может работать нестабильно.
 
но работает все ок, без сбоев
d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

andycat пишет:

328 чип

Скетч использует 19380 байт (60%) памяти устройства. Всего доступно 32256 байт.
Глобальные переменные используют 1641 байт (80%) динамической памяти, оставляя 407 байт для локальных переменных. Максимум: 2048 байт.
Недостаточно памяти, программа может работать нестабильно.
 
но работает все ок, без сбоев

а можешь скинуть скетч? посмотрим почему так много

 

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

я себе сократил на 700байт

 

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

у меня щас этот скетч занимает:

Скетч использует 23644 байт (76%) памяти устройства. Всего доступно 30720 байт.
Глобальные переменные используют 770 байт (37%) динамической памяти, оставляя 1278 байт для локальных переменных. Максимум: 2048 байт.
 
andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

да пожалуйста,

но мне не надо ничего сокращать :) - меня все устраивает,

потому не тратьте свое время на ковыряние чужого кода.

#include <avr/wdt.h>
#include <EEPROM.h>
// address 0 = count control users phone
// address 1.... control users phones, first char - A - active D - deleted, last char = 0
#include "a6modem.h"
#include <OneWire.h>
#include <DallasTemperature.h>
#include <RCSwitch.h>

#define max_time_read_sms 120000UL // 2min
#define max_time_read_command 10000UL // 10sec
#define startEEPROMmessages 128 // 0 position = byte - current save posifion from 0
#define endEEPROMmessages 383
#define max_count_users_phone 6
#define max_len_sms 250
#define keypad_pin A0
#define min_time_period_key_press 1000
#define alarm_pin A1
#define rc_reciv_pin 2
#define ds18b20_pin 3
#define period_get_internal_temp 317947 // ~ 5 min
#define pos_eeprom_relay1_mode 450 // 0 or FF - off 12 -on
#define pos_eeprom_relay2_mode 452 // 0 or FF - off 21 -on
#define pos_eeprom_count_reset_timeout 454

OneWire oneWire(ds18b20_pin);
DallasTemperature sensors(&oneWire);
RCSwitch mySwitch = RCSwitch();

unsigned long time_read_sms;
unsigned long time_read_command;
unsigned long time_unpress_key;
byte gsmmode, submode;
char OPSname[] = "Russia00";
char OPSbalance[] = "*99999#";
char* UnitCommands[] = {"addphone", "delphone", "getuptime", "getbalance", "gettemp", "resetmodem", "relay1on", "relay1off", "relay2on", "relay2off", "getrelay"};
char sender[24];
char smsmsg[max_len_sms];
char begstr[] = "~NEWsSMS~";
char endstr[] = "~SUCCSMS~";
boolean sw_lcd_light;
unsigned long time_sw_lcd_light;
boolean req_temp;
byte internal_temp;
byte external_temp;
unsigned long time_get_internal_temp;
unsigned long time_req_internal_temp;
word mas_str_temp[10];
byte med_str_pos = 0;
byte med_str_cnt = 0;
boolean minus_str_temp = false;

void setup() {
  // put your setup code here, to run once:
  firststart();
}

void loop() {
  // put your main code here, to run repeatedly:
  wdt_reset();
  unsigned long current_millis = millis();
  // lcd backlight control
  if (!sw_lcd_light) {
    word palm = analogRead(alarm_pin);
    if (palm < 500) {
      time_sw_lcd_light = current_millis;
      sw_lcd_light = true;
      digitalWrite(10, HIGH);
    }
  } else {
    if ((current_millis - time_sw_lcd_light) >= 30000) { // 30 sec - lcd light on
      sw_lcd_light = false;
      digitalWrite(10, LOW);
    }
  }
  // end lcd backlight control
  // get ext temp
  if (mySwitch.available()) {
    unsigned long receivedCode =  mySwitch.getReceivedValue();
    mySwitch.resetAvailable();
    if ((receivedCode >= 11500UL) && (receivedCode <= 14750UL)) {
      receivedCode -= 11500;
      if (((receivedCode >= 2000UL) && (receivedCode <= 2600UL)) || ((receivedCode >= 0UL) && (receivedCode <= 400UL))) {
        if ((receivedCode <= 400UL)) {
          receivedCode = 2000UL - receivedCode;
        }
        // correct temp
        if (receivedCode <= 1900UL) {
          receivedCode -= 12UL; // 1.2 degree
        } else {
          if (receivedCode <= 1950UL) {
            receivedCode -= 8UL; // 0.8 degree
          }
          else {
            if (receivedCode <= 1999UL) {
              receivedCode -= 5UL; // 0.5 degree
            }
          }
        }
        // --
        mas_str_temp[med_str_pos] = (word)(receivedCode);
        if ((++med_str_pos) >= 10) {
          med_str_pos = 0;
        }
        if ((++med_str_cnt) >= 10) {
          med_str_cnt = 10;
        }
        word sum_temp = 0;
        for (int i = 0; i < med_str_cnt; ++i) {
          sum_temp += mas_str_temp[i];
        }
        sum_temp /= med_str_cnt;
        if (sum_temp < 2000) {
          minus_str_temp = true;
          sum_temp = 2000 - sum_temp;
        } else {
          minus_str_temp = false;
          sum_temp -= 2000;
        }
        sum_temp /= 10;
        external_temp = (byte)(sum_temp);
      }
    }
  }
  // end get ext temp
  byte result = a6work();
  if ((result == 1) || (result == 2)) {
    if (result == 1) {
      domainmode();
    } else {
      //timeout
      byte br = EEPROM.read(pos_eeprom_count_reset_timeout);
      if (br == 0xFF) br = 0;
      ++br;
      EEPROM.write(pos_eeprom_count_reset_timeout, br);
      wdt_disable();
      a6resetmodem();
      unsigned long delp = millis(); while ((millis() - delp) <= 20000); // boot modem
      firststart();
    }
  } else {
    // other action
    // read sms mode
    if ((current_millis - time_read_sms) >= max_time_read_sms) {
      if (gsmmode == 1) {
        if (a6sendcmd("AT+CMGL=4", "OK", "", "", true) == 1) { // read SMS, =0 unread, =4 all
          gsmmode = 2; submode = 0; // mode read sms
          time_read_sms = current_millis; // after sucess send command read sms
        }
      }
    }
    // end read sms mode
    // read sms from eeprom for execute comand
    if ((current_millis - time_read_command) >= max_time_read_command) {
      if (gsmmode == 1) {
        time_read_command = current_millis;
        readSMSforCommand();
      }
    }
    // end read command
    // read key pad
    if (gsmmode == 1) {
      if ((current_millis - time_unpress_key) >= min_time_period_key_press) {
        word kp = analogRead(keypad_pin);
        byte key_mode;
        if ((kp > 600) && (kp < 700)) {
          key_mode = 0;
        } else {
          if ((kp > 370) && (kp < 450)) {
            key_mode = 1;
          } else {
            if ((kp > 80) && (kp < 120)) {
              key_mode = 2;
            } else {
              if ((kp > 216) && (kp < 296)) {
                key_mode = 3;
              } else {
                if (kp < 20) {
                  key_mode = 4;
                } else {
                  key_mode = 5; // not press
                }
              }
            }
          }
        }
        if (key_mode < 5) {
          time_unpress_key = current_millis;
          switch (key_mode) {
            case 0: {
                char strtemp[4];
                SendStrToLCD("Int=");
                strtemp[0] = '0' + internal_temp / 10;
                strtemp[1] = '0' + internal_temp % 10;
                strtemp[2] = 0;
                SendStrToLCD(strtemp);
                SendStrToLCD(" Ext=");
                if (minus_str_temp) strtemp[0] = '-'; else strtemp[0] = '+';
                strtemp[1] = '0' + external_temp / 10;
                strtemp[2] = '0' + external_temp % 10;
                strtemp[3] = 0;
                SendStrToLCD(strtemp);
                SendStrToLCD(" ");
                break;
              }
            case 1: {
                if (a6sendcmd("AT+CREG?", "OK", "", "", true) == 1) {
                  gsmmode = 3; submode = 1;
                }
                break;
              }
            case 2: {
                byte i = 0;
                while ((smsmsg[i] = OPSname[i]) != 0 ) ++i;
                smsmsg[i] = ' '; ++i;
                i = addTextUptime(i);
                smsmsg[i] = 0;
                SendStrToLCD(smsmsg);
                break;
              }
            case 3: {
                gsmmode = 100;
                // show phones from eeprom
                byte pc = EEPROM.read(0);
                if (pc == 0xFF) pc = 0;
                for (byte i = 0; ((i < pc) && (i < max_count_users_phone)); ++i) {
                  byte possend = 0; boolean fle = true;
                  word startpos = 1 + i * 14;
                  if (EEPROM.read(startpos) == 'A') sender[possend] = 'A'; else sender[possend] = 'D';
                  ++possend; sender[possend] = ' '; ++possend;
                  byte j = 0;
                  while (EEPROM.read(startpos + j + 1) != 0) {
                    sender[possend] = EEPROM.read(startpos + j + 1);
                    ++j; ++possend;
                  }
                  sender[possend] = ' '; ++possend; sender[possend] = 0;
                  SendStrToLCD(sender);
                  unsigned long delp = millis(); while ((millis() - delp) <= 2000);
                }
                // end show phones
                resetModeAndClearRespBuf();
                break;
              }
            case 4: {
                if (a6sendcmd("AT+CSQ", "OK", "", "", true) == 1) {
                  gsmmode = 3; submode = 1;
                }
                break;
              }
            default: {
              }
          }
        }
      }
    }
    // end key pad
    // req temp
    if ((current_millis - time_req_internal_temp) >= period_get_internal_temp) {
      if ((gsmmode == 1) && (!req_temp)) {
        time_req_internal_temp = current_millis;
        sensors.requestTemperatures();
        req_temp = true;
        time_get_internal_temp = current_millis;
      }
    }
    // end req temp -> get temp
    if ((current_millis - time_get_internal_temp) >= 1200) {
      if ((gsmmode == 1) && (req_temp)) {
        internal_temp = sensors.getTempCByIndex(0);
        req_temp = false;
      }
    }
    // end get internal temp
  }
}

void domainmode() {
  switch (gsmmode) {
    case 0: { // init modem
        switch (submode) {
          case 0: { // wait reponse first command AT
              if (a6sendcmd("ATE0", "OK", "", "", true) == 1) submode = 1; // no echo
              break;
            }
          case 1: { // wait reponse command ATE0
              if (a6sendcmd("ATV1", "OK", "", "", true) == 1) submode = 2; // get text for error
              break;
            }
          case 2: { // wait reponse command ATV1
              if (a6sendcmd("AT+CMEE=2", "OK", "", "", true) == 1) submode = 3; // get full text error
              break;
            }
          case 3: { // wait reponse command cmee
              if (a6sendcmd("AT+CLIP=1", "OK", "", "", true) == 1) submode = 4; // on aon
              break;
            }
          case 4: { // wait reponse command clip
              if (a6sendcmd("ATS0=3", "OK", "", "", true) == 1) submode = 5; // 3 ring
              break;
            }
          case 5: { // wait reponse command ats
              unsigned long delp = millis(); while ((millis() - delp) <= 30000); //delay for registration
              if (a6sendcmd("AT+CREG?", "+CREG: 1,1", "OK", "", true) == 1) submode = 6; // true registration
              //if (a6sendcmd("AT+CREG?", "OK", "", "", true) == 1) submode = 6; // registration
              break;
            }
          case 6: { // wait registration
              if (a6sendcmd("AT+CMGF=0", "OK", "", "", true) == 1) submode = 7; // mode SMS = PDU
              break;
            }
          case 7: { // wait mode sms
              if (a6sendcmd("AT+CMGD=1,4", "OK", "", "", true) == 1) submode = 8; // delete all sms
              break;
            }
          case 8: { // wait del sms
              if (a6sendcmd("AT+COPS?", "+COPS:", "OK", "", true) == 1) submode = 9; // load operator data
              break;
            }
          case 9: { // decode operator data
              a6getopsname(OPSname, OPSbalance);
              resetModeAndClearRespBuf(); // init ok
              digitalWrite(LED_BUILTIN, HIGH);
              SendByteToLCD(32, true);
              SendByteToLCD(223, false);
              SendByteToLCD(32, true);
              SendByteToLCD(226, false);
              SendByteToLCD(32, true);
              SendByteToLCD(241, false);
              SendByteToLCD(229, false);
              SendByteToLCD(242, false);
              SendByteToLCD(232, false);
              SendByteToLCD(32, true);
              SendByteToLCD('!', true);
              SendByteToLCD(32, true);
              wdt_enable(WDTO_8S);
              break;
            }
        }
        break;
      }
    case 1: { // main loop
        break;
      }
    case 2: { // mode read sms
        switch (submode) {
          case 0: {
              byte countsms = a6getcountsms();
              if (countsms > 0) {
                while (countsms > 0) { // loop by sms
                  a6readsms(countsms, sender, smsmsg);
                  if ((getAllowCommandPhone(sender) == 1) || (getAllowCommandPhone(sender) == 2)) {
                    // save sms to eeprom
                    saveSMStoEEPROM(sender, smsmsg);
                  }
                  // - end loop sms
                  --countsms;
                }
                // delete all sms
                if (a6sendcmd("AT+CMGD=1,4", "OK", "", "", true) == 1) submode = 1;
              } else {
                resetModeAndClearRespBuf(); // no sms
              }
              break;
            }
          default: {
              resetModeAndClearRespBuf();
            }
        }
        break;
      }
    case 3: { // mode send sms and mode test commands
        switch (submode) {
          case 0: {
              if (a6sendcmd(smsmsg, "+CMGS:", "OK", "", false) == 1) submode = 1;
              break;
            }
          default: {
              resetModeAndClearRespBuf();
            }
        }
        break;
      }
    case 4: { // mode get balance
        switch (submode) {
          case 0: {
              // decode USSD
              // send SMS text from USSD
              resetModeAndClearRespBuf(); // temp text, need submode = 1
              break;
            }
          default: {
              resetModeAndClearRespBuf();
            }
        }
        break;
      }
    default: {
        a6clearrespbuf();
      }
  }
}

void firststart() {
  pinMode(A0, INPUT_PULLUP);
  pinMode(A1, INPUT_PULLUP);
  pinMode(10, OUTPUT);
  pinMode(rc_reciv_pin, INPUT);
  digitalWrite(10, LOW); // LCD backlight control
  sensors.begin();
  time_req_internal_temp = 0;
  req_temp = false;
  sw_lcd_light = false;
  gsmmode = 0; submode = 0; // start
  time_read_sms = 0UL; time_read_command = 0UL;
  mySwitch.enableReceive(0);
  pinMode(A2, OUTPUT); // relay 1
  pinMode(A3, OUTPUT); // relay 2
  // on off relay
  if (EEPROM.read(pos_eeprom_relay1_mode) == 12) digitalWrite(A2, HIGH); else digitalWrite(A2, LOW);
  if (EEPROM.read(pos_eeprom_relay2_mode) == 21) digitalWrite(A3, HIGH); else digitalWrite(A3, LOW);
  // end on off relay
  pinMode(A4, OUTPUT); digitalWrite(A4, LOW);
  pinMode(A5, OUTPUT); digitalWrite(A5, LOW);
  a6initmodem(9600); // work - hard uart
}

void SerialPrintWin1251(char* textsms) {
  byte i = 0;
  while (textsms[i] != 0) {
    byte wb = textsms[i];
    if (wb <= 128) {
      Serial.write(wb);
    } else {
      switch (wb) {
        case 168: {
            Serial.write(208); Serial.write(101);
            break;
          }
        case 184: {
            Serial.write(209); Serial.write(145);
            break;
          }
        default: {
            if (wb < 192) {
              Serial.write(wb);
            } else {
              if (wb < 240) {
                Serial.write(208); Serial.write(wb - 48);
              } else {
                Serial.write(209); Serial.write(wb - 112);
              }
            }
          }
      }
    }
    ++i;
  }
}

byte getAllowCommandPhone(char* sender) {
  if (strPos(sender, ADMIN_PHONE) >= 0) return 2;
  word rb = FindPhomeFromUsersList(sender);
  if ((rb > 1000) && (rb < 2000)) {
    return 1;
  } else {
    return 0;
  }
}

void saveSMStoEEPROM(char* sender, char* textsms) {
  byte l1 = strlen(sender); byte l2 = strlen(textsms);
  word lastpos = EEPROM.read(startEEPROMmessages);
  if ((lastpos == 0xFF) || ((lastpos + l1 + l2 + 12) >= (endEEPROMmessages - startEEPROMmessages))) lastpos = 0;
  lastpos += (startEEPROMmessages + 1); byte i = 0;
  while (begstr[i] != 0) {
    EEPROM.write(lastpos + i, begstr[i]); ++i;
  }
  EEPROM.write(lastpos + i, 0);
  lastpos += (i + 1); i = 0;
  while (sender[i] != 0) {
    EEPROM.write(lastpos + i, sender[i]); ++i;
  }
  EEPROM.write(lastpos + i, 0);
  lastpos += (i + 1); i = 0;
  while (textsms[i] != 0) {
    EEPROM.write(lastpos + i, textsms[i]); ++i;
  }
  EEPROM.write(lastpos + i, 0);
  lastpos += (i + 1);
  EEPROM.write(startEEPROMmessages, (lastpos - startEEPROMmessages - 1));
}

void readSMSforCommand() {
  word lastpos = startEEPROMmessages + 1;
  word i, j, k;
m3:  i = 0; j = 0; k = 0;
m1:  byte eb = EEPROM.read(lastpos + i);
  if ((eb == begstr[i]) || (eb == endstr[i])) {
    if (eb == begstr[i]) ++j; if (eb == endstr[i]) ++k;
    if ((++i) >= 9) goto m2;
    goto m1;
  } else {
    return;
  }
m2:  if (k == 9) {
    // skip -> new sms
    lastpos += (k + 1);
    // find 0 and 0
    i = 0; while (EEPROM.read(lastpos + i) != 0) ++i;
    lastpos += (i + 1);
    if (lastpos >= endEEPROMmessages) return;
    i = 0; while (EEPROM.read(lastpos + i) != 0) ++i;
    lastpos += (i + 1);
    if (lastpos >= endEEPROMmessages) return;
    goto m3;
  }
  if (j == 9) {
    // save to eeprom ~SUCCSMS~
    i = 0;
    while ((endstr[i]) != 0) {
      EEPROM.write((lastpos + i), endstr[i]);
      ++i;
    }
    // new command
    lastpos += (j + 1); i = 0;
    while ((sender[i] = EEPROM.read(lastpos + i)) != 0) ++i;
    sender[i] = 0;
    lastpos += (i + 1); i = 0;
    while ((smsmsg[i] = EEPROM.read(lastpos + i)) != 0) ++i;
    smsmsg[i] = 0;
    lastpos += (i + 1);
    // find command
    j = 0; // num found command
    for (i = 0; i < 11; ++i) { // 11 commands
      if (strPos(smsmsg, UnitCommands[i]) >= 0) {
        j = i + 1;
        break;
      }
    }
    switch (j) {
      case 1: {
          if (getAllowCommandPhone(sender) != 2) return; // command for admin only
          if (CutPhoneFromText(smsmsg) != 1) return;
          // save phone to eeprom
          AddPhoneToUsersList(smsmsg);
          break;
        }
      case 2: {
          if (getAllowCommandPhone(sender) != 2) return; // command for admin only
          if (CutPhoneFromText(smsmsg) != 1) return;
          // delete phone from eeprom
          DelPhoneToUsersList(smsmsg);
          break;
        }
      case 3: {
          if (getAllowCommandPhone(sender) == 0) return; // command for any user
          // prepare send text
          i = 0;
          while ((smsmsg[i] = OPSname[i]) != 0 ) ++i;
          smsmsg[i] = ' '; ++i;
          i = addTextUptime(i);
          smsmsg[i] = 0;
          sendSMS();
          break;
        }
      case 4: {
          if (getAllowCommandPhone(sender) == 0) return; // command for any user
          char strcmd[] = "AT+CUSD=1,";
          i = 0;
          while ((sender[i] = strcmd[i]) != 0) ++i;
          j = 0;
          while ((sender[i] = OPSbalance[j]) != 0) {
            ++i; ++j;
          }
          sender[i] = ','; ++i; sender[i] = '1'; ++i; sender[i] = '5'; ++i;
          sender[i] = 0;
          a6sendcmd(sender, "OK", "+CUSD: 2,", ",72", true);
          gsmmode = 4; submode = 0;
          break;
        }
      case 5: {
          if (getAllowCommandPhone(sender) == 0) return; // command for any user
          // prepare send text
          char strtemp[] = "Int=";
          i = 0;
          while ((smsmsg[i] = strtemp[i]) != 0 ) ++i;
          strtemp[0] = '0' + internal_temp / 10;
          strtemp[1] = '0' + internal_temp % 10;
          strtemp[2] = 0;
          j = 0;
          while ((smsmsg[i] = strtemp[j]) != 0 ) {
            ++i; ++j;
          }
          smsmsg[i] = ','; ++i;
          strtemp[0] = 'E'; strtemp[1] = 'x'; strtemp[2] = 't'; strtemp[3] = '='; strtemp[4] = 0;
          j = 0;
          while ((smsmsg[i] = strtemp[j]) != 0 ) {
            ++i; ++j;
          }
          if (minus_str_temp) strtemp[0] = '-'; else strtemp[0] = '+';
          strtemp[1] = '0' + external_temp / 10;
          strtemp[2] = '0' + external_temp % 10;
          strtemp[3] = 0;
          j = 0;
          while ((smsmsg[i] = strtemp[j]) != 0 ) {
            ++i; ++j;
          }
          smsmsg[i] = ','; ++i;
          i = addTextUptime(i);
          smsmsg[i] = 0;
          sendSMS();
          break;
        }
      case 6: {
          if (getAllowCommandPhone(sender) == 0) return; // command for any user
          byte br = EEPROM.read(pos_eeprom_count_reset_timeout);
          if (br == 0xFF) br = 0;
          ++br;
          EEPROM.write(pos_eeprom_count_reset_timeout, br);
          wdt_disable();
          a6resetmodem();
          unsigned long delp = millis(); while ((millis() - delp) <= 20000); // boot modem
          firststart();
          break;
        }
      case 7: {
          if (getAllowCommandPhone(sender) == 0) return; // command for any user
          EEPROM.write(pos_eeprom_relay1_mode, 12);
          digitalWrite(A2, HIGH);
          break;
        }
      case 8: {
          if (getAllowCommandPhone(sender) == 0) return; // command for any user
          EEPROM.write(pos_eeprom_relay1_mode, 00);
          digitalWrite(A2, LOW);
          break;
        }
      case 9: {
          if (getAllowCommandPhone(sender) == 0) return; // command for any user
          EEPROM.write(pos_eeprom_relay2_mode, 21);
          digitalWrite(A3, HIGH);
          break;
        }
      case 10: {
          if (getAllowCommandPhone(sender) == 0) return; // command for any user
          EEPROM.write(pos_eeprom_relay2_mode, 00);
          digitalWrite(A3, LOW);
          break;
        }
      case 11: {
          if (getAllowCommandPhone(sender) == 0) return; // command for any user
          // prepare send text
          char strtemp[] = "Rl1";
          i = 0;
          while ((smsmsg[i] = strtemp[i]) != 0 ) ++i;
          if (EEPROM.read(pos_eeprom_relay1_mode) == 12) {
            strtemp[0] = 'o'; strtemp[1] = 'n'; strtemp[2] = 0;
          } else {
            strtemp[0] = 'o'; strtemp[1] = 'f'; strtemp[2] = 'f'; strtemp[3] = 0;
          }
          j = 0;
          while ((smsmsg[i] = strtemp[j]) != 0 ) {
            ++i; ++j;
          }
          smsmsg[i] = ','; ++i;
          strtemp[0] = 'R'; strtemp[1] = 'l'; strtemp[2] = '2'; strtemp[3] = 0;
          j = 0;
          while ((smsmsg[i] = strtemp[j]) != 0 ) {
            ++i; ++j;
          }
          if (EEPROM.read(pos_eeprom_relay2_mode) == 21) {
            strtemp[0] = 'o'; strtemp[1] = 'n'; strtemp[2] = 0;
          } else {
            strtemp[0] = 'o'; strtemp[1] = 'f'; strtemp[2] = 'f'; strtemp[3] = 0;
          }
          j = 0;
          while ((smsmsg[i] = strtemp[j]) != 0 ) {
            ++i; ++j;
          }
          smsmsg[i] = ','; ++i;
          i = addTextUptime(i);
          smsmsg[i] = 0;
          sendSMS();
          break;
        }
      default: {
        }
    }
  } else {
    return;
  }
}

byte CutPhoneFromText(char* smstxt) {
  int pp = strPos(smstxt, "+79");
  if (pp > 0) {
    byte cb = 0;
    for (byte i = 0; i < 12; ++i) { // +7 and 10 digit
      smstxt[cb] = smstxt[pp + cb]; ++cb;
    }
    smstxt[cb] = 0;
    if (cb == 12) return 1;
  }
  return 0;
}

void AddPhoneToUsersList(char* phoneNumber) {
  word rb = FindPhomeFromUsersList(phoneNumber);
  if (rb > 2000) {
    // set active number
    EEPROM.write((rb - 2000), 'A');
    return;
  }
  if (rb > 1000) {
    return;
  }
  // add new number
  byte pc = EEPROM.read(0);
  if (pc == 0xFF) pc = 0;
  if (pc >= max_count_users_phone) pc = 5; // last number;
  word startpos = 1 + (pc * 14);
  byte i = 0;
  EEPROM.write(startpos, 'A');
  while (phoneNumber[i] != 0) {
    EEPROM.write((startpos + 1 + i), phoneNumber[i]);
    ++i;
  }
  EEPROM.write((startpos + 1 + i), 0);
  ++pc;
  EEPROM.write(0, pc);
}

void DelPhoneToUsersList(char* phoneNumber) {
  word rb = FindPhomeFromUsersList(phoneNumber);
  if (rb > 1000) {
    // set delete number
    EEPROM.write((rb - 1000), 'D');
    return;
  }
}

word FindPhomeFromUsersList(char* phoneNumber) {
  byte pc = EEPROM.read(0);
  if (pc == 0xFF) pc = 0;
  if (pc == 0) {
    return 0;
  }
  byte i; boolean fla = false;
  for (i = 0; ((i < pc) && (i < max_count_users_phone)); ++i) {
    boolean fle = true;
    word startpos = 1 + i * 14;
    if (EEPROM.read(startpos) == 'A') fla = true; else fla = false;
    byte j = 0;
    while (phoneNumber[j] != 0) {
      if (phoneNumber[j] != EEPROM.read(startpos + j + 1)) {
        fle = false;
        break;
      }
      ++j;
    }
    if (fle) {
      if (fla) {
        return (1000 + startpos);
      } else {
        return (2000 + startpos);
      }
    }
  }
  return 0;
}

byte addTextUptime(byte firstpos) {
  unsigned long cml = millis() / 1000UL;
  byte days = cml / 86400;
  byte hours = (cml % 86400) / 3600;
  byte mins = ((cml % 86400) % 3600) / 60;
  if (days > 9) {
    smsmsg[firstpos] = (days / 10) + '0';
    ++firstpos;
  }
  smsmsg[firstpos] = (days % 10) + '0'; ++firstpos;
  smsmsg[firstpos] = 228; ++firstpos; smsmsg[firstpos] = 237; ++firstpos; smsmsg[firstpos] = '.'; ++firstpos;
  if (hours > 9) {
    smsmsg[firstpos] = (hours / 10) + '0';
    ++firstpos;
  }
  smsmsg[firstpos] = (hours % 10) + '0'; ++firstpos;
  smsmsg[firstpos] = 247; ++firstpos; smsmsg[firstpos] = 224; ++firstpos; smsmsg[firstpos] = 241; ++firstpos;
  smsmsg[firstpos] = '.'; ++firstpos;
  if (mins > 9) {
    smsmsg[firstpos] = (mins / 10) + '0';
    ++firstpos;
  }
  smsmsg[firstpos] = (mins % 10) + '0'; ++firstpos;
  smsmsg[firstpos] = 236; ++firstpos; smsmsg[firstpos] = 232; ++firstpos; smsmsg[firstpos] = 237; ++firstpos;
  smsmsg[firstpos] = '.'; ++firstpos;
  // add count timeout reset
  smsmsg[firstpos] = 'R'; ++firstpos;
  byte br = EEPROM.read(pos_eeprom_count_reset_timeout);
  smsmsg[firstpos] = '0' + (br / 100); ++firstpos;
  smsmsg[firstpos] = '0' + ((br % 100) / 10); ++firstpos;
  smsmsg[firstpos] = '0' + ((br % 100) % 10); ++firstpos;
  smsmsg[firstpos] = '.'; ++firstpos;
  return firstpos;
}

void sendSMS() {
  // convert msg to pdu format
  byte lenTextByChar = strlen(smsmsg);
  // move text to end buf
  byte i, j;
  for (i = 0; i < lenTextByChar; ++i) {
    smsmsg[max_len_sms - lenTextByChar + i] = smsmsg[i];
  }
  byte curr_pos_pdu = 0;
  smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; // SCA field
  smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = '1'; ++curr_pos_pdu; // PDU type
  smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; // MR
  byte lenSenderPhone = strlen(sender);
  if (lenSenderPhone != 12) return;
  smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = 'B'; ++curr_pos_pdu; // DA-PL
  smsmsg[curr_pos_pdu] = '9'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = '1'; ++curr_pos_pdu; // DA-PT
  // convert sender number
  for (i = 0; i < lenSenderPhone; ++i) {
    sender[i] = sender[i + 1];
  }
  sender[lenSenderPhone - 1] = 'F'; sender[lenSenderPhone] = 0;
  for (i = 0; i < lenSenderPhone; i += 2) {
    j = sender[i + 1];
    sender[i + 1] = sender[i];
    sender[i] = j;
  }
  for (i = 0; i < lenSenderPhone; ++i) { // DA-RP
    smsmsg[curr_pos_pdu] = sender[i];
    ++curr_pos_pdu;
  }
  smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; // PID field
  smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = '8'; ++curr_pos_pdu; // DCS field
  lenTextByChar *= 2; // UDL
  byte bb = lenTextByChar / 16;
  if (bb < 10) {
    smsmsg[curr_pos_pdu] = (bb + '0'); ++curr_pos_pdu;
  } else {
    smsmsg[curr_pos_pdu] = (bb + '0' + 7); ++curr_pos_pdu;
  }
  bb = lenTextByChar % 16;
  if (bb < 10) {
    smsmsg[curr_pos_pdu] = (bb + '0'); ++curr_pos_pdu;
  } else {
    smsmsg[curr_pos_pdu] = (bb + '0' + 7); ++curr_pos_pdu;
  }
  // UD - text by UCS2
  for (i = 0; i < (lenTextByChar / 2); ++i) {
    bb = smsmsg[max_len_sms - (lenTextByChar / 2) + i];
    if (bb < 0x7F) {
      smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu;
      // convert to hex
      j = bb / 16;
      if (j < 10) {
        smsmsg[curr_pos_pdu] = (j + '0'); ++curr_pos_pdu;
      } else {
        smsmsg[curr_pos_pdu] = (j + '0' + 7); ++curr_pos_pdu;
      }
      j = bb % 16;
      if (j < 10) {
        smsmsg[curr_pos_pdu] = (j + '0'); ++curr_pos_pdu;
      } else {
        smsmsg[curr_pos_pdu] = (j + '0' + 7); ++curr_pos_pdu;
      }
    } else {
      switch (bb) {
        case 168: {
            smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = '4'; ++curr_pos_pdu;
            smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = '1'; ++curr_pos_pdu;
            break;
          }
        case 184: {
            smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = '4'; ++curr_pos_pdu;
            smsmsg[curr_pos_pdu] = '5'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = '1'; ++curr_pos_pdu;
            break;
          }
        default: {
            if (bb < 192) {
              smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu;
              // convert to hex
              j = bb / 16;
              if (j < 10) {
                smsmsg[curr_pos_pdu] = (j + '0'); ++curr_pos_pdu;
              } else {
                smsmsg[curr_pos_pdu] = (j + '0' + 7); ++curr_pos_pdu;
              }
              j = bb % 16;
              if (j < 10) {
                smsmsg[curr_pos_pdu] = (j + '0'); ++curr_pos_pdu;
              } else {
                smsmsg[curr_pos_pdu] = (j + '0' + 7); ++curr_pos_pdu;
              }
            } else {
              smsmsg[curr_pos_pdu] = '0'; ++curr_pos_pdu; smsmsg[curr_pos_pdu] = '4'; ++curr_pos_pdu;
              // convert to hex
              j = (bb - 176) / 16;
              if (j < 10) {
                smsmsg[curr_pos_pdu] = (j + '0'); ++curr_pos_pdu;
              } else {
                smsmsg[curr_pos_pdu] = (j + '0' + 7); ++curr_pos_pdu;
              }
              j = (bb - 176) % 16;
              if (j < 10) {
                smsmsg[curr_pos_pdu] = (j + '0'); ++curr_pos_pdu;
              } else {
                smsmsg[curr_pos_pdu] = (j + '0' + 7); ++curr_pos_pdu;
              }
            }
          }
      }
    }
  }
  // -
  smsmsg[curr_pos_pdu] = 26;
  smsmsg[curr_pos_pdu + 1] = 0;
  char strcmd[] = "AT+CMGS=";
  i = 0;
  while ((sender[i] = strcmd[i]) != 0) ++i;
  sender[i] = ((curr_pos_pdu / 2 - 1) / 10) + '0'; ++i;
  sender[i] = ((curr_pos_pdu / 2 - 1) % 10) + '0'; ++i;
  sender[i] = 0;
  a6sendcmd(sender, ">", "", "", false);
  gsmmode = 3; submode = 0;
}

void resetMode() {
  gsmmode = 1; submode = 0; // main loop
}

void resetModeAndClearRespBuf() {
  resetMode();
  a6clearrespbuf();
}

 

// functions for a6 gsm modem
#include "Arduino.h"
#include <SoftwareSerial.h>

#define _a6_power_pin 12
#define _a6_reset_pin 11

#define RESPONSE_BUF_SIZE 250
#define RESPONSE_DETECT_SIZE 16
#define RESPONSE_MAX_TIME 30000
#define ADMIN_PHONE "+7920***9946"

void a6initmodem(word a6uartspeed);
byte a6sendcmd(char* txtcmd, char* resp1, char* resp2, char* resp3, boolean show_cmd);
byte a6work();
byte a6detectresp(char* resp1, char* resp2, char* resp3);
char* LastPos(char *str1, char *str2);
int strPos(char *str11, char *str22);
void a6clearrespbuf();
void a6resetmodem();
byte a6getcountsms();
byte a6readsms(byte indexsms, char* phonenumber, char* textsms);
void a6decodepdusms(byte firstcharpdu, byte counttextpdu, byte lastcharpdu, char* senderphone, char* textsms);
byte strHexTobyte(char p1, char p2);
void a6decodetextpdu7bit(byte charcount, byte firstpos, char* textsms);
void a6decodetextpduUCS2(byte bytecount, byte firstpos, char* textsms);
void a6getopsname(char* opsname, char* opsbalance);
void SendByteToLCD(byte inByte, boolean ET);
void SendStrToLCD(char* latinStr);

 

// functions for a6 gsm modem
#include "a6modem.h"
#include "Arduino.h"
#include <LiquidCrystal_1602_RUS.h>

char _rsp_buf[RESPONSE_BUF_SIZE];
word _rsp_pos;
char _resp_detect1[RESPONSE_DETECT_SIZE]; char _resp_detect2[RESPONSE_DETECT_SIZE]; char _resp_detect3[RESPONSE_DETECT_SIZE];
unsigned long cmd_started_time;
boolean wait_response;
char* OPSlist[] = {"TELE2RUS", "*105#", "25020", "Beeline", "*100#", "25099", "MegaFon", "*100#", "25002", "MTS", "*100#", "25001"};
char OPScode[] = "250000";
byte IdxLCD = 0; // 0..31 - char on LCD

LiquidCrystal_1602_RUS LCD(8, 9, 4, 5, 6, 7 );//For LCD Keypad Shield

// a6 init modem
// p1 - modem speed
// p2 - 1=use Software Serial UART
// p3 - Serial0 speed, use as console, =0 if dont use or modem use Serial0;
void a6initmodem(word a6uartspeed) {
  // init LCD
  LCD.begin(16, 2);
  LCD.clear();
  LCD.setCursor(0, 0);
  IdxLCD = 0;
  SendByteToLCD(209, false);
  SendByteToLCD(242, false);
  SendByteToLCD(224, false);
  SendByteToLCD(240, false);
  SendByteToLCD(242, false);
  SendByteToLCD(32, true);
  SendStrToLCD("Start ");
  LCD.cursor();
  LCD.blink();
  // init modem
  pinMode(_a6_reset_pin, OUTPUT);
  pinMode(_a6_power_pin, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
  digitalWrite(_a6_reset_pin, LOW);
  digitalWrite(_a6_power_pin, HIGH); // power on
  unsigned long delp = millis(); while ((millis() - delp) <= 10000);
  Serial.begin(a6uartspeed);
  // adaptive speed a6 module
  unsigned long curr_millis = millis();
  while ((millis() - curr_millis) <= 4000UL) Serial.println("AT");
  curr_millis = millis();
  while ((millis() - curr_millis) <= 5000UL) if (Serial.available()) while (Serial.available()) Serial.read();
  // -
  wait_response = false;
  a6sendcmd("AT", "OK", "", "", true); // begin work
}

void a6resetmodem() {
  // reset modem
  digitalWrite(_a6_reset_pin, HIGH);
  unsigned long delp = millis(); while ((millis() - delp) <= 500);
  digitalWrite(_a6_reset_pin, LOW);
}

byte a6sendcmd(char* txtcmd, char* resp1, char* resp2, char* resp3, boolean show_cmd) {
  if (wait_response) return 0;
  Serial.println(txtcmd);
  if (show_cmd) SendStrToLCD(txtcmd);
  cmd_started_time = millis();
  a6clearrespbuf();
  byte pp = 0;
  if (resp1[0] == 0) {
    wait_response = false;
    _resp_detect1[0] = 0;
    return 1;
  } else {
    wait_response = true;
    pp = 0;
    while ((resp1[pp] != 0) && (pp < (RESPONSE_DETECT_SIZE - 1))) {
      _resp_detect1[pp] = resp1[pp];
      ++pp;
    }
    _resp_detect1[pp] = 0;
  }
  pp = 0;
  while ((resp2[pp] != 0) && (pp < (RESPONSE_DETECT_SIZE - 1))) {
    _resp_detect2[pp] = resp2[pp];
    ++pp;
  }
  _resp_detect2[pp] = 0;
  pp = 0;
  while ((resp3[pp] != 0) && (pp < (RESPONSE_DETECT_SIZE - 1))) {
    _resp_detect3[pp] = resp3[pp];
    ++pp;
  }
  _resp_detect3[pp] = 0;
  return 1;
}

byte a6work() {
  boolean getdata = false;
  if (Serial.available())
    while (Serial.available())
      if (_rsp_pos < (RESPONSE_BUF_SIZE - 1)) {
        _rsp_buf[_rsp_pos] = Serial.read();
        ++_rsp_pos;
        getdata = true;
      }
  if (getdata) {
    _rsp_buf[_rsp_pos] = 0;
    if (_rsp_pos > 0) {
      if (_rsp_pos <= 32) SendStrToLCD(_rsp_buf);
    }
  }
  // wait response for sent at command
  if (wait_response) {
    if ((millis() - cmd_started_time) >= RESPONSE_MAX_TIME) {
      wait_response = false;
      return 2; // timeout
    } else {
      if (a6detectresp(_resp_detect1, _resp_detect2, _resp_detect3)) {
        wait_response = false;
        return 1; // OK
      }
    }
  }
  return 0;
}

void a6clearrespbuf() {
  _rsp_pos = 0; _rsp_buf[_rsp_pos] = 0;
}

byte a6detectresp(char* resp1, char* resp2, char* resp3) {
  if (_rsp_pos > 0) {
    if (resp1[0] != 0) {
      if (strPos(_rsp_buf, resp1) >= 0) {
        if (resp2[0] == 0) {
          return 1;
        } else {
          if (strPos(_rsp_buf, resp2) >= 0) {
            if (resp3[0] == 0) {
              return 1;
            } else {
              if (strPos(_rsp_buf, resp3) >= 0) {
                return 1;
              } else {
                return 0;
              }
            }
          } else {
            return 0;
          }
        }
      } else {
        return 0;
      }
    } else {
      return 0;
    }
  } else {
    return 0;
  }
}

char* LastPos(char *str1, char *str2) {
  int L1 = strlen(str1);
  int L2 = strlen(str2);
  for (int i = L1 - L2; i >= 0; i--)
  {
    int j = 0;
    for (; j < L2; j++)
      if (str1[i + j] != str2[j])
        break;
    if (j == L2)
      return str1 + i;
  }
  return 0;
}

int strPos(char *str11, char *str22) {
  char*p = LastPos(str11, str22);
  int n = p - str11;
  return n;
}

byte a6getcountsms() {
  char findstr[] = "+CMGL:";
  if (a6detectresp(findstr, "", "") == 0) return 0;
  byte result = 0;
  int L1 = strlen(_rsp_buf);
  int L2 = strlen(findstr);
  for (int i = L1 - L2; i >= 0; i--)
  {
    int j = 0;
    for (j = 0; j < L2; j++)
      if (_rsp_buf[i + j] != findstr[j])
        break;
    if (j == L2) {
      ++result;
    }
  }
  return result;
}

byte a6readsms(byte indexsms, char* phonenumber, char* textsms) {
  phonenumber[0] = 0; textsms[0] = 0;
  byte numfirstchar;
  if (indexsms < 10) {
    char findstr[] = "+CMGL: 1"; findstr[7] = '0' + indexsms;
    numfirstchar = strPos(_rsp_buf, findstr);
    numfirstchar += (strlen(findstr) + 4); // first posifion = count byte of pdu message
  } else {
    char findstr[] = "+CMGL: 1 "; findstr[8] = '0' + (indexsms % 10);
    numfirstchar = strPos(_rsp_buf, findstr);
    numfirstchar += (strlen(findstr) + 4); // first posifion = count byte of pdu message
  }
  // get lenght pdu
  byte i = 0;
  byte countbytepdu = 0;
  while (isdigit(_rsp_buf[numfirstchar + i])) {
    if (i > 0) {
      countbytepdu = (countbytepdu * 10) + (_rsp_buf[numfirstchar + i] - '0');
    } else {
      countbytepdu = _rsp_buf[numfirstchar + i] - '0';
    }
    ++i;
  }
  numfirstchar += i;
  if ((_rsp_buf[numfirstchar] == '\r') && (_rsp_buf[numfirstchar + 1] == '\n')) { // find first CR LF
    numfirstchar += 2;
  } else {
    return;
  }
  i = 0;
  while (!((_rsp_buf[numfirstchar + i] == '\r') && (_rsp_buf[numfirstchar + 1 + i] == '\n') && (_rsp_buf[numfirstchar + i] != 0))) { // find last CR LF
    ++i;
  }
  byte numlastchar = numfirstchar + i - 1;
  a6decodepdusms(numfirstchar, countbytepdu, numlastchar, phonenumber, textsms);
}

void a6decodepdusms(byte firstcharpdu, byte counttextpdu, byte lastcharpdu, char* senderphone, char* textsms) {
  // firstcharpdu - pos TP-SCA + 1 byte size
  byte nf = strHexTobyte(_rsp_buf[firstcharpdu], _rsp_buf[firstcharpdu + 1]) + 1; // new pos =  TP-MTI & Co
  ++nf; // new pos = TP-OA
  byte lf = strHexTobyte(_rsp_buf[firstcharpdu + (nf * 2)], _rsp_buf[firstcharpdu + (nf * 2) + 1]); // lenght sender phone number
  // check format number
  ++nf;
  if ((_rsp_buf[firstcharpdu + (nf * 2)] != '9') || (_rsp_buf[firstcharpdu + (nf * 2) + 1] != '1')) return; // not digit format
  ++nf;
  senderphone[0] = '+';
  for (byte i = 0; i < lf; ++i) {
    senderphone[i + 1] = _rsp_buf[firstcharpdu + (nf * 2) + i + 1];
    senderphone[i + 2] = _rsp_buf[firstcharpdu + (nf * 2) + i];
    ++i;
  }
  nf *= 2;
  nf += lf;
  if (senderphone[lf] == 'F') senderphone[lf] = 0; else senderphone[lf + 1] = 0;
  ++nf; // next char - pos TP-PID
  nf += 2; // pos TP-DCS
  boolean flUCS2;
  if ((_rsp_buf[firstcharpdu + nf] == '0') && (_rsp_buf[firstcharpdu + nf + 1] == '0')) flUCS2 = false; else flUCS2 = true;
  nf += 2; // pos TP-SCTS
  nf += 14; // pos TP-UDL
  byte lenpdutext = strHexTobyte(_rsp_buf[firstcharpdu + nf], _rsp_buf[firstcharpdu + nf + 1]);
  nf += 2; // pos TP-UD
  if (flUCS2) {
    a6decodetextpduUCS2(lenpdutext, (firstcharpdu + nf), textsms);
  } else {
    a6decodetextpdu7bit(lenpdutext, (firstcharpdu + nf), textsms);
  }
}

byte strHexTobyte(char p1, char p2) {
  p1 -= '0';
  if (p1 > 10) (p1 -= 7);
  p1 = p1 << 4;
  p2 -= '0';
  if (p2 > 10) (p2 -= 7);
  return (p1 | p2);
}

void a6decodetextpdu7bit(byte charcount, byte firstpos, char* textsms) {
  for (byte i = 0; i < charcount; ++i) {
    byte begin7bytepart = i / 8;
    byte resultbyte = 0;
    byte numbyte = i % 8;
    byte b1 = firstpos + (begin7bytepart * 2 * 8) + (numbyte * 2) - (2 * (begin7bytepart + 1));
    byte b2 = strHexTobyte(_rsp_buf[b1 + 2], _rsp_buf[b1 + 3]);
    b1 = strHexTobyte(_rsp_buf[b1], _rsp_buf[b1 + 1]);
    byte lowb;
    if (numbyte == 0) {
      lowb = b2;
    } else {
      if (numbyte < 7) (lowb = b2 << numbyte); else (lowb = 0);
    }
    byte hib;
    if (numbyte > 0) (hib = b1 >> (8 - numbyte)); else (hib = 0);
    resultbyte = hib | lowb;
    textsms[i] = resultbyte & 0x7F;
  }
  textsms[charcount] = 0;
}

void a6decodetextpduUCS2(byte bytecount, byte firstpos, char* textsms) {
  for (byte i = 0; i < bytecount; i += 2) {
    byte b1 = firstpos + (i * 2);
    byte b2 = strHexTobyte(_rsp_buf[b1 + 2], _rsp_buf[b1 + 3]);
    b1 = strHexTobyte(_rsp_buf[b1], _rsp_buf[b1 + 1]);
    if (b1 == 0) {
      textsms[i / 2] = b2;
    } else {
      byte rb;
      if (b1 == 0x04) {
        switch (b2) {
          case 0x01: {
              rb = 168;
              break;
            }
          case 0x51: {
              rb = 184;
              break;
            }
          default: {
              if ((b2 >= 0x10) && (b2 <= 0x4F)) {
                rb = b2 + 176;
              } else {
                rb = b2;
              }
            }
        }
      } else {
        rb = b2;
      }
      textsms[i / 2] = rb;
    }
  }
  textsms[bytecount / 2] = 0;
}

void a6getopsname(char* opsname, char* opsbalance) {
  boolean fl = false;
  byte i;
  for (i = 0; i < 12; ++i) {
    if (strPos(_rsp_buf, OPSlist[i]) >= 0) {
      fl = true;
      break;
    }
  }
  if (fl) {
    byte j = 0; while ((OPScode[j] = OPSlist[i][j]) != 0) ++j; OPScode[j] = 0;
    j = 0; while ((opsname[j] = OPSlist[i - 2][j]) != 0) ++j; opsname[j] = 0;
    j = 0; while ((opsbalance[j] = OPSlist[i - 1][j]) != 0) ++j; opsbalance[j] = 0;
  }
}

// send win1251 byte to LCD
void SendByteToLCD(byte inByte, boolean ET) {
  if (inByte == 13) {
    LCD.print(" ");
  } else {
    if (inByte < 0x20) return;
    if ((ET == true) && (inByte >= 0x7F)) return;
    if (ET == false) {
      if ((inByte == 168) || (inByte == 184) || ((inByte >= 192) && (inByte <= 255))) {
        LCD.print(LCD.asciiutf8(inByte));
      } else {
        LCD.print(char(inByte));
      }
    } else {
      LCD.print(char(inByte));
    }
  }
  switch (IdxLCD) {
    case 15: {
        LCD.setCursor(0, 1);
        ++IdxLCD;
        break;
      }
    case 31: {
        LCD.setCursor(0, 0);
        IdxLCD = 0;
        break;
      }
    default : {
        ++IdxLCD;
      }
  }
}

void SendStrToLCD(char* latinStr) {
  byte i = 0;
  while (latinStr[i] != 0) {
    SendByteToLCD(latinStr[i], false);
    ++i;
  }
}

 

b707
Offline
Зарегистрирован: 26.05.2017

andycat пишет:

наверное я такой криворукий, но у меня весь скетч на char[] и тоже занимает более 80 % динамической памяти,

250 байт входящий буфер от модема, 250 байт исходящий буфер для отправки SMS в PDU формате,

А нельзя использовать один буфер и для приема и для отправки? по-моему они не нужны одновременно...

 

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

b707 пишет:

andycat пишет:

наверное я такой криворукий, но у меня весь скетч на char[] и тоже занимает более 80 % динамической памяти,

250 байт входящий буфер от модема, 250 байт исходящий буфер для отправки SMS в PDU формате,

А нельзя использовать один буфер и для приема и для отправки? по-моему они не нужны одновременно...

 

Можно, но сразу сходу не получилось, так как отправка смс идёт двумя AT командами, а скетч универсальный под любые команды и передача смс самой идёт сразу после ответа на первую команду, т е в памяти желательно все держать и отправку и приём.

Как вариант использовать различную размер массивов и динамическое выделение памяти, но тогда теряется универсальность библиотеки которую я для А6 модема написал.

Короче все реально, нужно просто сесть и сделать, а на работе я иногда и работу работаю....лень доделывать - работает стабильно и хорошо. 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

d13lider пишет:

понял на счет F, супер, ноо большой ущерб памяти флеш... у меня и так флеша 76% на 328p-au

Не будет никакого ущерба. От слова совсем.

Если у Вас используются константные строки, то, когда МК выключен, они должны где-то храниться? Кроме как во flash, больше негде. Вопрос только в том, будут ли они перед применением копироваться в оперативную память или нет. А места занимают ровно столько же.

b707
Offline
Зарегистрирован: 26.05.2017

andriano пишет:

Не будет никакого ущерба. От слова совсем.

Если у Вас используются константные строки, то, когда МК выключен, они должны где-то храниться? Кроме как во flash, больше негде. Вопрос только в том, будут ли они перед применением копироваться в оперативную память или нет. А места занимают ровно столько же.

Вы ошибаетесь и весьма сильно. Макрос F() вообще ОЧЕНЬ НЕЭФФЕКТИВНО тратит флеш - он тратит флеша куда больше, чем экономит ОЗУ. Особенно это касается повторяющихся строк.

например, код

Serial.print("Bla-bla-bla!");
Serial.print("Bla-bla-bla!");
Serial.print("Bla-bla-bla!");
Serial.print("Bla-bla-bla!");
Serial.print("Bla-bla-bla!");

сохранит в ОЗУ только одну копию строки и потратит на это всего 12 байт, а такой же код с макросом F(), сэкономив 12 байт -  положит во флеш пять одинаковых строк по 12 байт,  не считая накладных расходов.

Можете легко убедится, компилируя коды в Ардуино ИДЕ.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

b707, Вы это серьезно?

Да, действительно, способ размещения констант в оперативной памяти и во флеш различается. Именно способ. Из этого следует, что в каких-то случаях оптимальнее окажется одно, в каких-то - другое. Вашь пример явно искусственный, поэтому ориентироваться на него как на правило, вряд ли следует.

В среднем при нормальном коде разницы практически нет. В частности, разница может быть как в плюс, так и в минус.

Но можно придумать частный случай, в котором разница окажется существенной.

В любом случае, ничто не отменаяет того положения, что любая уникальная строка, которая должна появиться в ОЗУ после включения питания, занимает место во flash памяти.

b707
Offline
Зарегистрирован: 26.05.2017

andriano пишет:

b707, Вы это серьезно?

В среднем при нормальном коде разницы практически нет. В частности, разница может быть как в плюс, так и в минус. Вашь пример явно искусственный, поэтому ориентироваться на него как на правило, вряд ли следует.

В любом случае, ничто не отменаяет того положения, что любая уникальная строка, которая должна появиться в ОЗУ после включения питания, занимает место во flash памяти.

Что, интересно, в этом коде искусственного? То, что строки повторяются?

Вы бы, вместо того, чтобы лозунгами писать - взяли бы и сначала убедились на практике. Возьмем максимально простой пример -одна уникальная строка.

void setup() {
  // put your setup code here, to run once:
}

void loop() {
  // put your main code here, to run repeatedly:
Serial.print("s");
}
Код - 1342 байта ОЗУ - 186

Далее меняем только строчку, поэтому буду указывать только оператор вывода и цифры:

Serial.print("sss");

Код - 1344 байта ОЗУ - 188

Пока все логично - дополнительные 2 символа заняли 2 лишних байта и в ОЗУ и в во флеш

Добавляем F()

Serial.print(F("sss"));
}
Код - 1366 байта ОЗУ - 184

Ну что, вы все еще считаете, что "разницы практически нет"?  Чтобы освободить 4 байта ОЗУ, макрос F() потратил аж 22 байта флеш.

Хотите дальше? - извольте! добавим еще одну строку, опять уникальную:

Serial.print(F("sss"));
Serial.print(F("ght"));

Код - 1414 байт, ОЗУ - 184

чтобы сравнение было корректным, тот же код без F()

Serial.print("sss");
Serial.print("ght");

Код - 1364 байт, ОЗУ - 192

Опять "разницы нет", правда?  Тут уже экономия 8 байт обошлась аж в 50 байт флеша...

Можно продолжать и дальше. При каждом использовании F() потери флеша будут разными. Но они всегда больше , чем экономия оперативки. Иногда разница в разы, как в примере выше - иногда почти то на то - но всегда НЕ МЕНЬШЕ.

Ну что, скажете, пример опять неудачен?

Приведите свой.

arduinec
Offline
Зарегистрирован: 01.09.2015

b707 пишет:

Ну что, скажете, пример опять неудачен? Приведите свой.

При выключении и включении питания строки без F() продолжают выводиться, значит они сохранены в флеш-памяти. Вопрос в том: почему с F() увеличивается расход флеша?

Клапауций 298
Клапауций 298 аватар
Offline
Зарегистрирован: 25.01.2018

arduinec пишет:

Вопрос в том: почему с F() увеличивается расход флеша?

нуу... порой исходники макроса F() - видимо они и занимают место на флеше.

b707
Offline
Зарегистрирован: 26.05.2017

arduinec пишет:

При выключении и включении питания строки без F() продолжают выводиться, значит они сохранены в флеш-памяти. Вопрос в том: почему с F() увеличивается расход флеша?

вопрос скорее надо ставить так - если это жестко кодированая строковая константа, зачем она вообще занимает место в оперативке?

А ответ на вопрос, почему макрос F() расходует столько флеша - это как раз просто. Этот макрос не является специализированным именно для констант, это "обертка" для типа FlashStringHelper. который работает не только с контантами, но и с переменными. Поэтому конструкция F("SSS") трактует "SSS" как переменную, которую надо перенести во флеш, оставив на месте ее вызова код, извлекающий строку из флеш-памяти.  Поэтому F() не только занимает 4 байта во флеш под строку, но и добавляет в код программы инструкции обратного извлечения этих байт в ОЗУ.

И, снова про повторяющиеся строки  - если макросу встречается пять одинаковых строк - он положит во флеш каждую отдельно, не анализируя. что такая строка уже там есть. Это, как я понимаю, тоже следствие того, что F() считает строки переменными.