struct array и PROGMEM - как записать структуру массива и сам строковый массив в Flash-память

traveler
Offline
Зарегистрирован: 27.09.2018

Добрый вечер! Прошу знатоков подсказать правильное задание структуры строковых массивов и задание значений элементов массива с записью в Flash-память, нужно для экономии динамической памяти Arduino Nano.

Код, который применяю:

#include <avr/pgmspace.h>

struct listUsr_t
{
  const char phoneNum[13];
  const char phonePass[5];
  const char phonePDU[13];
};

listUsr_t users[20] = 
{
  { "+70000000000", "0000", "000000000000" },
  { "+71111111111", "0000", "000000000000" },
  { "+78881234567", "0000", "000000000000" },
  { "+78882345678", "0000", "000000000000" },
  { "+78883456789", "0000", "000000000000" },
  { "+78884567890", "0000", "000000000000" },
  { "+78885678901", "0000", "000000000000" },
  { "+78886789012", "0000", "000000000000" },
  { "+78887890123", "0000", "000000000000" },
  { "+78888901234", "0000", "000000000000" },
  { "+78880123456", "0000", "000000000000" },
  { "+78881123456", "0000", "000000000000" },
  { "+78881234567", "0000", "000000000000" },
  { "+78881345678", "0000", "000000000000" },
  { "+78881456789", "0000", "000000000000" },
  { "+78881567890", "0000", "000000000000" },
  { "+78881678901", "0000", "000000000000" },
  { "+78881789012", "0000", "000000000000" },
  { "+78881890123", "0000", "000000000000" },
  { "+78881901234", "0000", "000000000000" } 
};

void setup()
{
  Serial.begin(9600);
  Serial.println(sizeof(users));
}

void loop()
{
  ;
}

Размер данных возвращается 620 байт, что соответствует действительности 13+5+13=31*20=620.

Подскажите, пожалуйста, как этот массив записать в Flash-память, при помощи pgmspace.h - я не могу разобраться, к сожалению... Заранее благодарен за помощь!

traveler
Offline
Зарегистрирован: 27.09.2018

Записать строковый массив без структуры - нет проблем:

#include <avr/pgmspace.h>

const char _phoneNum[2][13] PROGMEM = { "+70000000000", "+711111111111" };

Нужен массив со структурой...

Logik
Offline
Зарегистрирован: 05.08.2014

а const listUsr_t PROGMEM  users[20] = ....  не решает?

traveler
Offline
Зарегистрирован: 27.09.2018

Logik пишет:

а const listUsr_t PROGMEM  users[20] = ....  не решает?

Огромное спасибо! Я не мог понять почему ругается компилятор - PROGMEM ставил в разные места, объявляя массив со структурой, но забывал про const, теперь, массив со структурой задается и располагается в Flash-памяти... еще раз - спасибо!

strarbit
Offline
Зарегистрирован: 12.06.2016
traveler
Offline
Зарегистрирован: 27.09.2018

Спасибо! Я эту статью прочитал несколько раз, и не мог понять причину, искал в сторону pgmspace.h и синтаксиса этой библиотеки, а оказалось, я не правильно объявлял элемент, его нужно было как const объявлять.

sadman41
Offline
Зарегистрирован: 19.10.2016

По ссылке strarbit более правильный способ, ибо запихивание массива строк в pgmspace несколько специфичная задача.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Вроде вчера в другой теме было тоже самое и вновь опять #25

traveler
Offline
Зарегистрирован: 27.09.2018

sadman41 пишет:

По ссылке strarbit более правильный способ, ибо запихивание массива строк в pgmspace несколько специфичная задача.

Именно из-за специфичности задачи я и обратился к помощи более опытных коллег. Задача состоит в том, чтобы в 2048 байта уместить код с многими логическими функциями, и прочим кодом, отвечающим за контроль работы привода.

traveler
Offline
Зарегистрирован: 27.09.2018

qwone пишет:

Вроде вчера в другой теме было тоже самое и вновь опять #25

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

traveler
Offline
Зарегистрирован: 27.09.2018

Записать строки с необходимыми данными в Flash-память получилось, это очень сильно сэкономило память контроллера. Однако, теперь у меня новый тупик, я не могу считать строки, считывается только первый символ и все... вот код:

#include <avr/pgmspace.h>

const uint8_t cntLstPhones = 2;

struct listUsr_t
{
  const char phoneNum[13];
  const char phonePass[5];
  const char phonePDU[13];
  const char plot[9];
};

const listUsr_t PROGMEM users[cntLstPhones] = 
{
  { "+78881890123", "0000", "000000000000", "plot #" },
  { "+78881901234", "0000", "000000000000", "plot #" }
};

void setup()
{
  Serial.begin(57600);
  Serial.println(F("<== START of DATA ==>"));

char val;
val = (__FlashStringHelper*)(pgm_read_dword(&(users[1].phonePass)));
Serial.println(val);

Serial.println(F("<== END of DATA ==>"));
}

void loop()
{
  ;
}

При этом компилятор выдает предупреждение: "warning: invalid conversion from '__FlashStringHelper*' to 'char' [-fpermissive]", и в монитор Serial-порта выводится только первый символ строки, записанной в Flash-память, куда копать не могу разобраться, прошу помощи!!!

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

вы пытаетесь считывать строку в переменную val, которая обьявлена как char - то есть имеет размер 1 символ. Что же еще туда может считаться, кроме 1 символа?

traveler
Offline
Зарегистрирован: 27.09.2018

Я это понимаю, в глубине души, однако, при попытке задать размер строкового массива 

char val[5];

компилятор возвращает ошибку и прекращает компиляцию: "error: incompatible types in assignment of '__FlashStringHelper*' to 'char [5]'", у меня тупик, если честно...

Использовать strcpy_P ещё не пробовал, но это не путь, т.к. strcpy_P требует объявлять переменные, как глобальные, а глобальные переменные "скушают" память, динамическую, и вся экономия при помощи PROGMEM будет зря... Заранее благодарен, если подскажите правильный код для решения моей задачи.

 

sadman41
Offline
Зарегистрирован: 19.10.2016

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

Просто радуйтесь тому, что строки, расположенные в progmem не будут перегружаться в RAM и не будет двойного удара по ресурсам.

И мне все еще кажется, что в PGM вы засунули неправильно. Почитайте статью по ссылке strarbit - там есть специальный раздел "Array of string". Нужно делать именно так, во всех деталях, с раздельными объявлениями строк в PGM, а потом сборе в общий массив. Может сейчас компилятор и умничает, а года два назад такой способ, как приведен у вас, лично мне никак не помогал экономить.

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

traveler пишет:

Использовать strcpy_P ещё не пробовал, но это не путь, т.к. strcpy_P требует объявлять переменные, как глобальные

 

во-первых, это не так - strcpy_P работает и с локальными переменными. Во-вторых, даже если использовать глобальную переменную буфера  - то для strcpy_P она нужна всего одна на все ваши строки в ПРОГМЕМ, так что удар по ресурсам не так уж и велик.

Вам надо еще раз внимательно перечитать ссылки, которые вам дали выше. Вам кажется, что они не про ваш случай, что он уникален - но он получается уникальным именно потому, что вы подходите к хранению строк неправильно. Сделайте как по ссылке и все получится.

traveler
Offline
Зарегистрирован: 27.09.2018

Если речь идет о том, что сначала необходимо задать строковые массивы, потом создать таблицу с указанием на созданные строковые массивы и считывать при помощи pgm_read_dword или pgm_read_word в буфер или созданную переменную (почему-то пишется, что только глобальную), то это я знаю, но в таком случае не будет структуры... НО и без структуры можно обойтись, весь проблемный для меня вопрос, это то, что один из строковых массивов имеет длину 250 символов, и если даже, я сделаю, как написано в описании работы (ссылка предложенная выше по этому обсуждению, то у меня получиться 20% сразу долой из памяти контроллера, это для меня не решение задачи.

Кроме того, как объяснить тот факт, что код вида:

#include <avr/pgmspace.h>
 
const uint8_t cntLstPhones = 2;
struct listUsr_t
{
  const char phoneNum[13];
  const char phonePass[5];
  const char phonePDU[13];
  const char plot[9];
};

const listUsr_t PROGMEM users[cntLstPhones] =
{
  { "+78881890123", "0000", "000000000000", "plot #" },
  { "+78881901234", "0000", "000000000000", "plot #" }
};

void setup()
{

  Serial.begin(57600);

  Serial.println(F("<== START of DATA ==>"));

 for (uint8_t i = 0; i < cntLstPhones; i++)
    {
      printUsr(users[i], i);
    }
Serial.println(F("<== END of DATA ==>"));
}

 void loop()
{
  ;
}

void printUsr(const listUsr_t &user, uint8_t numPhone)
{
  Serial.println(numPhone + 1);
  Serial.println((const __FlashStringHelper*)user.phoneNum);
  Serial.println((const __FlashStringHelper*)user.phonePass);
  Serial.println((const __FlashStringHelper*)user.phonePDU);
  Serial.println((const __FlashStringHelper*)user.Plot);
}

Этот код выводит в монитор Serial-порта все строки правильно... значит в Flash-память они помещены тоже правильно... Кто может помочь - буду благодарен!!!

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Ну-ну. Похоже это башня из доминошек. Лишний чих и сново-здорово.

#include <avr/pgmspace.h>
 
const uint8_t cntLstPhones = 2;
struct listUsr_t
{
  const char phoneNum[13];
  const char phonePass[5];
  const char phonePDU[13];
  const char plot[9];
};

const listUsr_t PROGMEM users[cntLstPhones] =
{
  { "+78881890123", "0000", "000000000000", "plot #" },
  { "+78881901234", "00000", "000000000000", "plot #" } //<- а теперь ко второму элементу добавим лишний 0
};

void setup()
{

  Serial.begin(9600);

  Serial.println(F("<== START of DATA ==>"));

 for (uint8_t i = 0; i < cntLstPhones; i++)
    {
      printUsr(users[i], i);
    }
Serial.println(F("<== END of DATA ==>"));
}

 void loop()
{
  ;
}

void printUsr(const listUsr_t &user, uint8_t numPhone)
{
  Serial.println(numPhone + 1);
  Serial.println((const __FlashStringHelper*)user.phoneNum);
  Serial.println((const __FlashStringHelper*)user.phonePass);
  Serial.println((const __FlashStringHelper*)user.phonePDU);
  Serial.println((const __FlashStringHelper*)user.plot);
}

 

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

traveler пишет:

НО и без структуры можно обойтись, весь проблемный для меня вопрос, это то, что один из строковых массивов имеет длину 250 символов,

весь массив 250 символов или КАЖДЫЙ элемент 250?

Если у вас отдельный элемент 250 символов - то как ни старайся, вам придется копировать его в память. Или выводить по частям. Может в таком случае вы просто не тот контроллер взяли? В Меге 8к памяти, а в СТМ32 - аж целых 20к, стоит посмотреть на них.

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

traveler пишет:

Этот код выводит в монитор Serial-порта все строки правильно... значит в Flash-память они помещены тоже правильно... Кто может помочь - буду благодарен!!!

если этот код работает - используйте его

sadman41
Offline
Зарегистрирован: 19.10.2016

Ну, вобщем, советовать как лучше решить задачу, смысла которой не знаешь, абсолютно бессмысленно. 

Почему вы решили, что нельзя создать стуктуру с указателями на PGM-строки - мне тоже не особо понятно.  Переменных в 250 символов я тут у вас не вижу.

traveler
Offline
Зарегистрирован: 27.09.2018

b707 пишет:

весь массив 250 символов или КАЖДЫЙ элемент 250?

Если у вас отдельный элемент 250 символов - то как ни старайся, вам придется копировать его в память. Или выводить по частям. Может в таком случае вы просто не тот контроллер взяли? В Меге 8к памяти, а в СТМ32 - аж целых 20к, стоит посмотреть на них.

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

если этот код работает - используйте его

каждый по 250 символов....

использовать код - я не могу понять, как сравнить строку записанную в Flash-память со строкой в динамической памяти, сравнивать нужно строки длиной 13 и 5 символов, соответсвенно строка 13 символов сравнивается со строкой из 13 символов, 13-й символ это \0, завершающий.

Строки из 250 сивловов используются для отправки сообщений при помощи модуля SIM800, в PDU режиме, кодировать в скетче, опять же, много памяти расходуется...

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

 

sadman41
Offline
Зарегистрирован: 19.10.2016

traveler пишет:

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

https://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html#gab0c75b8cce460448b747c29231da847c <<The strcmp_P() function is similar to strcmp() except that s2 is pointer to a string in program space

traveler
Offline
Зарегистрирован: 27.09.2018

sadman41 пишет:

Ну, вобщем, советовать как лучше решить задачу, смысла которой не знаешь, абсолютно бессмысленно. 

Почему вы решили, что нельзя создать стуктуру с указателями на PGM-строки - мне тоже не особо понятно.  Переменных в 250 символов я тут у вас не вижу.

Структуру я создал и строковые массивы с заданной структурой я записал в флеш-память (в коде, прикрепленном мной это видно). Правильность записанных строковых массивов проверяю, пока, пуьем вывода в монитор Serial-порта (также, видно в моем коде).

Задача состоит в том, что при входящем вызове (модуль SIM800), средствами модуля определяем номер телефона, и необходимо сравнить определившийся номер с номерами из массива, номера из массива перебираем при помощи цикла for, если хоть один номера из массива совпадает, то выполняется действие (digitalWrite pin), если не один номер не совпал, то отбой звонка, примерно такая стоит задача.

Строки в 250 символов (максималная длина) это сообщения в PDU режиме для того же модуля, они ни с чем не сравниваются, с их использованием собираются смс-сообщения на русском языке (PDU mode).

Я не могу разобраться, как сравнить строку 13 или 5 символов в флеш-памяти с соответсвующей строкой в динамической памяти контроллера, за помощь или подсказку буду очень признателен!

sadman41
Offline
Зарегистрирован: 19.10.2016

Ну, может как-то так (на МК не заливал)?

  char incomingNumber[] = "70000000003";
  digitalWrite(13, LOW);
  for (uint8_t i = 0; i < 3; i++) {
    if (0x00 == strcnmp_P(incomingNumber, users[i].phoneNum, 13)) {
      digitalWrite(13, HIGH);
    }
  }

 

traveler
Offline
Зарегистрирован: 27.09.2018

sadman41 пишет:

Ну, может как-то так (на МК не заливал)?

  char incomingNumber[] = "70000000003";
  digitalWrite(13, LOW);
  for (uint8_t i = 0; i < 3; i++) {
    if (0x00 == strcnmp_P(incomingNumber, users[i].phoneNum, 13)) {
      digitalWrite(13, HIGH);
    }
  }

 

Спасибо огромное!

Я тоже смотрел описание этого макроса - буду пробовать использовать сравнение из PGM, по результатам отпишусь, ещё раз - спасибо!

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

traveler пишет:

Строки из 250 сивловов используются для отправки сообщений при помощи модуля SIM800, в PDU режиме, кодировать в скетче, опять же, много памяти расходуется...

 


Кодируйте динамически

traveler
Offline
Зарегистрирован: 27.09.2018

sadman41 пишет:

Ну, может как-то так (на МК не заливал)?

  char incomingNumber[] = "70000000003";
  digitalWrite(13, LOW);
  for (uint8_t i = 0; i < 3; i++) {
    if (0x00 == strcnmp_P(incomingNumber, users[i].phoneNum, 13)) {
      digitalWrite(13, HIGH);
    }
  }

 

Доброе утро! Ещё раз спасибо! Код залил на МК - всё работает, память отбирается соответственно переменным, все ОК! Код не много дополнил, в связи с тем, что определение номера идет в String:

String innerPhone = "+70001234567";  // номер входящего вызова, определяемый другой функцией (SIM800)
char incPhone[13];
innerPhone.toCharArray(incPhone, 13);
if (strncmp_P(incPhone, users[i].phoneNum, 13) == 0x00) Serial.println(F("true"));
else Serial.println(F("false"));

Логику и действия с пинами МК - это уже готово, практически, главная задача была уместиться в отведенные 2048 байт памяти МК. На данный момент, все константы с номерами, паролями, текмстовыми сообщениями в нескольких форматах, загружаются в флеш-память, расход динамической памяти 10%, ранее было 52%, экономия присутствует...

Ещё раз спасибо всем за помощь и консультации!

traveler
Offline
Зарегистрирован: 27.09.2018

Теперь остался один непонятный для меня момент в работе с PGM. Как сравнить строки из ОЗУ и Флеш, разобрался с общей помощью, а как "вытащить" строку из флеш-памяти, чтобы "собрать" необходимый пакет в строку, из нескольких строк, несколько частей составной строки находится в ОЗУ в виде локальных переменных в конкретной функции, а некоторые части составной строки находятся в флеш-памяти.

Подскажите как "вытащить" строку из флеш-памяти в локальную переменную в ОЗУ или сразу добавить в составную строку часть из флеш-памяти???

traveler
Offline
Зарегистрирован: 27.09.2018

andycat пишет:
Кодируйте динамически

Памяти не хватает!!!

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

traveler пишет:

andycat пишет:
Кодируйте динамически

Памяти не хватает!!!

У меня все хватает, логику поменяйте, в пн могу скинуть часть скетча.

traveler
Offline
Зарегистрирован: 27.09.2018

andycat пишет:
traveler пишет:

andycat пишет:
Кодируйте динамически

Памяти не хватает!!!

У меня все хватает, логику поменяйте, в пн могу скинуть часть скетча.

буду признателен!

sadman41
Offline
Зарегистрирован: 19.10.2016

1) У класса String имеется свойство, дающее указатель типа char* - копировать не надо в буфер. 

2) По ссылке на nongnu перечислены все функции, работающие с pgm - например strncpy_p()

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

traveler пишет:

буду признателен!

Там относительно просто, используется буфер для исходного сообщения размером максимум 70 байт (максимум для одного смс по русски по стандартам) в однобайтовой кодировке, например win1251. Отсылает сначала заголовки pdu, потом цикл по буферу и каждый символ на ходу переводите UCS2 кодировку и отсылаете.
У меня объем всего скетча вроде половины (не помню точно - в пн скажу) памяти уно со следующим функционалом: приём ( в т ч длинных) и отправка смс в pdu формате, обработка присылаемых команд, работа с олед дисплеем, отображение напряжения питания модема, аптайм и пр.
И да - привыкайте работать со строками char - пригодится

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

как и обещал, часть скетча (4 файла из 5), вдруг пригодится:

//--s800str.h--
#include <avr\pgmspace.h>

#define maxSizeATcommand 40
#define maxSizeResponse 24

#define count_ext_cmd 3

// only ascii chars
const char extCmd1[] PROGMEM = "getuptime";
const char extCmd2[] PROGMEM = "getpower";
const char extCmd3[] PROGMEM = "getbalmegafon";

const char * const ext_cmd_list[] PROGMEM = { // external commands
  extCmd1, extCmd2, extCmd3
};

void getExtCmdByNum(byte numCmd, char* textCmd);

const char at0cmdAT[] PROGMEM = "AT\r\n";
const char at1cmdHTTPACTION[] PROGMEM = "AT+HTTPACTION=0\r\n";
const char at1rsp1[] PROGMEM = "+HTTPACTION:";
const char at1rsp2[] PROGMEM = ",";
const char at2cmdSAPBR11[] PROGMEM = "AT+SAPBR=1,1\r\n";
const char at2rsp1[] PROGMEM = "operation not allowed\r\n";
const char at3cmdREADSMS[] PROGMEM = "AT+CMGL=4\r\n"; // "AT+CMGL=\"ALL\"\r\n";
const char at4cmdDDET[] PROGMEM = "AT+DDET=1\r\n";
const char at5cmdATE0[] PROGMEM = "ATE0\r\n";
const char at6cmdCLIP1[] PROGMEM = "AT+CLIP=1\r\n";
const char at7cmdATS0[] PROGMEM = "ATS0=0\r\n";
const char at8cmdATV1[] PROGMEM = "ATV1\r\n";
const char at9cmdATCMEE2[] PROGMEM = "AT+CMEE=2\r\n";
const char at10cmdATCMGF1[] PROGMEM = "AT+CMGF=0\r\n";
const char at11cmdATCREG[] PROGMEM = "AT+CREG?\r\n";
const char at11rsp1[] PROGMEM = "+CREG:";
const char at11rsp2[] PROGMEM = ",1\r\n";
const char at12cmdDELSMS[] PROGMEM = "AT+CMGDA=6\r\n"; // "AT+CMGDA=\"DEL ALL\"\r\n";
const char at13cmdSAPBR311[] PROGMEM = "AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"\r\n";
const char at14cmdSAPBR312[] PROGMEM = "AT+SAPBR=3,1,\"APN\",\"internet\"\r\n";
const char at15cmdSAPBR313[] PROGMEM = "AT+SAPBR=3,1,\"USER\",\"\"\r\n";
const char at16cmdSAPBR314[] PROGMEM = "AT+SAPBR=3,1,\"PWD\",\"\"\r\n";
const char at17cmdSAPBR21[] PROGMEM = "AT+SAPBR=2,1\r\n";
const char at17rsp1[] PROGMEM = "+SAPBR:";
const char at17rsp2[] PROGMEM = ",1,\"";
const char at18cmdHTTPINIT[] PROGMEM = "AT+HTTPINIT\r\n";
const char at19cmdHTTPCID[] PROGMEM = "AT+HTTPPARA=\"CID\",1\r\n";
const char at20cmdHTTPURL[] PROGMEM = "AT+HTTPPARA=\"URL\",\"www.ya.ru\"\r\n";
const char at21cmdHTTPREAD[] PROGMEM = "AT+HTTPREAD\r\n";
const char at22cmdHTTPTERM[] PROGMEM = "AT+HTTPTERM\r\n";
const char at23cmdCSCLK1[] PROGMEM = "AT+CSCLK=1\r\n"; // =1 if use DTR pin modem
const char at24cmdGETOPS[] PROGMEM = "AT+COPS?\r\n"; // get operator
const char at25cmdCSQ[] PROGMEM = "AT+CSQ\r\n"; // get net
const char at26cmdCMGS[] PROGMEM = "AT+CMGS="; // begin send sms
const char at26rsp1[] PROGMEM = ">"; // begin send sms
const char at27cmdCMGS[] PROGMEM = "none"; // text sms
const char at27rsp1[] PROGMEM = "+CMGS:"; // text sms
const char at28cmdBALMEG[] PROGMEM = "AT+CUSD=1,\"*100#\"\r\n"; // get balance megafon
const char at28rsp1[] PROGMEM = "+CUSD:";
const char at28rsp2[] PROGMEM = ", 72\r\n";

const char rspOK[] PROGMEM = "OK\r\n";
const char rspEndLine[] PROGMEM = "\r\n";

const char * const at_list_cmd[] PROGMEM = { // text command
  at0cmdAT, at1cmdHTTPACTION, at2cmdSAPBR11, at3cmdREADSMS, at4cmdDDET,
  at5cmdATE0, at6cmdCLIP1, at7cmdATS0, at8cmdATV1, at9cmdATCMEE2,
  at10cmdATCMGF1, at11cmdATCREG, at12cmdDELSMS, at13cmdSAPBR311,
  at14cmdSAPBR312, at15cmdSAPBR313, at16cmdSAPBR314, at17cmdSAPBR21,
  at18cmdHTTPINIT, at19cmdHTTPCID, at20cmdHTTPURL, at21cmdHTTPREAD, at22cmdHTTPTERM,
  at23cmdCSCLK1, at24cmdGETOPS, at25cmdCSQ, at26cmdCMGS, at27cmdCMGS,
  at28cmdBALMEG
};

const PROGMEM  uint8_t at_rresp_cmd[] = { // 0-count right response
  1, 4, 0, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3
};

const PROGMEM  uint8_t at_oresp_cmd[] = { // 1-count other response - need manual action by response
  0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

const PROGMEM  uint8_t at_move_cmd[] = { // step after action cmd
  4, 21, 17, 12, 5, 6, 7, 8, 9, 10, 11, 13, 101, 14, 15, 16, 23, 18, 19, 20, 1, 22, 101, 24, 12, 101, 27, 101, 101
};

const char * const at_list_rresp[] PROGMEM = {
  rspOK, // at0
  rspOK, at1rsp1, at1rsp2, rspEndLine, // at1
  rspOK, // at3
  rspOK, // at4
  rspOK, // at5
  rspOK, // at6
  rspOK, // at7
  rspOK, // at8
  rspOK, // at9
  rspOK, // at10
  at11rsp1, at11rsp2, rspOK, // at11
  rspOK, // at12
  rspOK, // at13
  rspOK, // at14
  rspOK, // at15
  rspOK, // at16
  at17rsp1, at17rsp2, rspOK, // at17
  rspOK, // at18
  rspOK, // at19
  rspOK, // at20
  rspOK, // at21
  rspOK, // at22
  rspOK, // at23
  rspOK, // at24
  rspOK, // at25
  at26rsp1, // at26
  at27rsp1, rspOK, // at27
  rspOK, at28rsp1, at28rsp2 // at28
};

const char * const at_list_oresp[] PROGMEM = {
  rspOK, at2rsp1 // at2
};

void s800getTextCmdByNum(byte numCmd, char* textCmd);
byte s800getCountRrespCmdByNum(byte numCmd);
byte s800getCountOrespCmdByNum(byte numCmd);
void s800getRespByNum(byte typeResp, byte numCmd, byte numResp, char* textCmd);
byte s800getNextStepCmdByNum(byte numCmd);

#define GSM_RX 3 // пин RX на модуле подключаем к указаному пину на Ардуино TX
#define GSM_TX 2 // пин TX на модуле подключаем к указаному пину на Ардуино RX

#define WORK_LEVEL_LED 0      // 1 if HIGH level ON led, else 0
#define WORK_LEVEL_RELAY 0    // 1 if HIGH level ON relay, else 0

#define reset_sim800_pin 4 // pin for reset modem
#define dtr_sim800_pin 10 // pin DTR for sleep mode

#define power_level_pin A6 // input power level for control

#define relay1_pin 6 // pin relay 1
#define relay2_pin 5 // pin relay 2
#define relay3_pin 9 // pin relay 3

#define ledRed_pin 7 // pin RED led
#define ledGre_pin 8 // pin GREEN led

#if (WORK_LEVEL_LED == 0)
#define LEDREDON digitalWrite(ledRed_pin,LOW)
#define LEDGREON digitalWrite(ledGre_pin,LOW)
#define LEDREDOFF digitalWrite(ledRed_pin,HIGH)
#define LEDGREOFF digitalWrite(ledGre_pin,HIGH)
#else
#define LEDREDON digitalWrite(ledRed_pin,HIGH)
#define LEDGREON digitalWrite(ledGre_pin,HIGH)
#define LEDREDOFF digitalWrite(ledRed_pin,LOW)
#define LEDGREOFF digitalWrite(ledGre_pin,LOW)
#endif

#if (WORK_LEVEL_RELAY == 0)
#define RELAY1ON digitalWrite(relay1_pin,LOW)
#define RELAY2ON digitalWrite(relay2_pin,LOW)
#define RELAY3ON digitalWrite(relay3_pin,LOW)
#define RELAY1OFF digitalWrite(relay1_pin,HIGH)
#define RELAY2OFF digitalWrite(relay2_pin,HIGH)
#define RELAY3OFF digitalWrite(relay3_pin,HIGH)
#else
#define RELAY1ON digitalWrite(relay1_pin,HIGH)
#define RELAY2ON digitalWrite(relay2_pin,HIGH)
#define RELAY3ON digitalWrite(relay3_pin,HIGH)
#define RELAY1OFF digitalWrite(relay1_pin,LOW)
#define RELAY2OFF digitalWrite(relay2_pin,LOW)
#define RELAY3OFF digitalWrite(relay3_pin,LOW)
#endif

char* LastPos(char *str1, char *str2);
int strPos(char *str11, char *str22);

//--s800str.cpp--
#include "Arduino.h"
#include "s800str.h"

void getExtCmdByNum(byte numCmd, char* textCmd) {
  const char * addrStroki = pgm_read_word_near((int)(ext_cmd_list + numCmd));
  strcpy_P(textCmd, addrStroki);
}

void s800getTextCmdByNum(byte numCmd, char* textCmd) {
  const char * addrStroki = pgm_read_word_near((int)(at_list_cmd + numCmd));
  strcpy_P(textCmd, addrStroki);
}

byte s800getCountRrespCmdByNum(byte numCmd) {
  return pgm_read_byte_near(at_rresp_cmd + numCmd);
}

byte s800getCountOrespCmdByNum(byte numCmd) {
  return pgm_read_byte_near(at_oresp_cmd + numCmd);
}

byte s800getNextStepCmdByNum(byte numCmd) {
  return pgm_read_byte_near(at_move_cmd + numCmd);
}

void s800getRespByNum(byte typeResp, byte numCmd, byte numResp, char* textCmd) {
  byte startPos = 0;
  if (numCmd > 0) for (byte i = 1; i <= numCmd; ++i) {
      switch (typeResp) {
        case 0: {
            startPos += pgm_read_byte_near(at_rresp_cmd + i - 1);
            break;
          }
        case 1: {
            startPos += pgm_read_byte_near(at_oresp_cmd + i - 1);
            break;
          }
        default : {}
      }
    }
  switch (typeResp) {
    case 0: {
        const char * addrStroki = pgm_read_word_near((int)(at_list_rresp + startPos + numResp));
        strcpy_P(textCmd, addrStroki);
        break;
      }
    case 1: {
        const char * addrStroki = pgm_read_word_near((int)(at_list_oresp + startPos + numResp));
        strcpy_P(textCmd, addrStroki);
        break;
      }
    default : {}
  }
}

char* LastPos(char *str1, char *str2) { // find substring in string
  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) { // find position in string(1) substring(2)
  char*p = LastPos(str11, str22);
  int n = p - str11;
  return n;
}


//--s800sms.h--

#define SHOW_SMS 1 // 1 show sms in console

#define max_size_sms_sender 12 // 11 + stopbyte;
#define max_size_cmd 16 // maximum size external command
#define max_size_out_sms 64 // maximum size out SMS by WIN1251 chars

void getDecode7bitChar(byte byte1, byte byte0);
byte getByteFromTwoChar(byte byte1, byte byte0);
void doSMSbody(byte readByte);
void doSMShead();
void cmdClearBuf();
byte findCmdInBuf(byte inByte);
byte findCmdFromBuf(char* textCmd);
void smsClearOut();
void smsPrepareSender(char* textSender);
void smsPrepareText(char* textText);
void smsPrepareText(byte inByte);
void smsPrepareOut();
byte smsOutPackedByte();
byte smsGetSizePDU();
byte doHaveSendSms();


//--s800sms.cpp--
#include "Arduino.h"
#include "s800str.h"
#include "s800sms.h"

extern void execExtCmd(byte numCmd);
extern byte pos_buf;
extern char resp_buf[maxSizeResponse];
byte pos_cmd;
char cmd_buf[max_size_cmd];

char sms_buf[max_size_out_sms];
byte sms_out_size_packet;
byte sms_out_pos_sender;
byte sms_out_pos_string;
byte sms_out_pos_other;
byte sms_out_pos_mode;
byte smsLenSender;
byte smsLenString;
byte smsUDL;

void cmdClearBuf() {
  memset(cmd_buf, 0, max_size_cmd);
  pos_cmd = 0;
}

byte findCmdInBuf(byte inByte) {
  cmd_buf[pos_cmd] = inByte;
  ++pos_cmd;
  if (pos_cmd >= max_size_cmd) pos_cmd = 0;
  char ext_cmd[max_size_cmd];
  for (byte i = 0; i < count_ext_cmd; ++i) {
    getExtCmdByNum(i, ext_cmd);
    if (findCmdFromBuf(ext_cmd)) {
      cmdClearBuf();
      return (i + 1);
    }
  }
  return 0;
}

byte findCmdFromBuf(char* textCmd) {
  if (cmd_buf[pos_cmd] > 0) {
    byte idxBuf;
    if (pos_cmd == 0) idxBuf = max_size_cmd - 1; else idxBuf = pos_cmd - 1;
    byte lenResp = strlen(textCmd);
    byte idxResp = lenResp - 1;
    byte cntResp = 0;
    for (byte i = 0; i < max_size_cmd; ++i) {
      if (cmd_buf[idxBuf] == 0) break;
      if (cmd_buf[idxBuf] == textCmd[idxResp]) {
        --idxResp;
        if ((++cntResp) == lenResp) return 1;
      } else {
        cntResp = 0; idxResp = lenResp - 1;
      }
      if ((--idxBuf) == 0) idxBuf = max_size_cmd - 1;
    }
  } else if (pos_cmd > 0) {
    if (strPos(cmd_buf, textCmd) >= 0) {
      return 1;
    }
  }
  return 0;
}

byte smsStep = 0;
//99 start new sms
byte smsOriginalSize;
byte smsOriginalPosByte;
byte smsTmpByte;
byte smsSizePhone;
byte smsBodyPosByte;
byte smsTPMTICO;
byte smsTPUDHI;
char smsSender[max_size_sms_sender];
byte smsTPOA;
byte smsTmpSize;
byte smsTPDCS;
byte smsPrevDecodeByte;
byte smsIdxCurrentChar;
byte smsUDHL;
byte smsIEDL;
byte smsIED;

void getDecode7bitChar(byte byte1, byte byte0) {
  byte posIdx = smsIdxCurrentChar % 8;
  byte byteOut;
  if (posIdx > 0) {
    byteOut =  byte0 << posIdx;
    byte b2 = byte1 >> (8 - posIdx);
    byteOut = byteOut | b2;
    byteOut = byteOut & 0x7F;
    if (byte1) {
#if (SHOW_SMS == 1)
      Serial.write(byteOut);
#endif
      // find external command
      byte bc = findCmdInBuf(byteOut);
      if (bc) execExtCmd(bc - 1);
    }
    if (posIdx == 6) {
      byteOut =  byte0 >> 1;
#if (SHOW_SMS == 1)
      Serial.write(byteOut);
#endif
      // find external command
      byte bc = findCmdInBuf(byteOut);
      if (bc) execExtCmd(bc - 1);
      ++smsIdxCurrentChar;
    }
  } else {
    byteOut = byte0;
    byteOut = byteOut & 0x7F;
#if (SHOW_SMS == 1)
    Serial.write(byteOut);
#endif
    // find external command
    byte bc = findCmdInBuf(byteOut);
    if (bc) execExtCmd(bc - 1);
  }
  ++smsIdxCurrentChar;
}

byte getByteFromTwoChar(byte byte1, byte byte0) {
  byte resultB;
  if (byte1 >= 0x41) resultB = (byte1 - 0x37) * 16; else  resultB = (byte1 - 0x30) * 16;
  if (byte0 >= 0x41) resultB = resultB + (byte0 - 0x37); else resultB = resultB + (byte0 - 0x30);
  return resultB;
}

void doSMShead() {
  // get length body sms
  byte posSbyte = 0;
  byte posBbyte = (pos_buf - 3);
  while ((resp_buf[posBbyte] >= 0x30) && (resp_buf[posBbyte] <= 0x39)) {
    if (posSbyte == 0) smsOriginalSize = (resp_buf[posBbyte] - 0x30);
    else if (posSbyte == 1) smsOriginalSize = smsOriginalSize + (resp_buf[posBbyte] - 0x30) * 10;
    else if (posSbyte == 2) smsOriginalSize = smsOriginalSize + (resp_buf[posBbyte] - 0x30) * 100;
    ++posSbyte;
    --posBbyte;
  }
  smsOriginalPosByte = 0;
  smsStep = 99;
}

void doSMSbody(byte readByte) {
  // get byte from buf
  ++smsOriginalPosByte;
  switch (smsStep) {
    case 99: { // get size sms centr
        if (bitRead(smsOriginalPosByte, 0)) {
          smsTmpByte = readByte;
        } else {
          smsSizePhone = getByteFromTwoChar(smsTmpByte, readByte);
          smsStep = 100;
        }
        break;
      }
    case 100: { // skip num sms centr
        if (!bitRead(smsOriginalPosByte, 0)) {
          if ((--smsSizePhone) == 0) {
            smsStep = 101;
            smsBodyPosByte = 0;
          }
        }
        break;
      }
    case 101: { // get TP-MTI & Co
        if (bitRead(smsOriginalPosByte, 0)) {
          smsTmpByte = readByte;
        } else {
          smsTPMTICO = getByteFromTwoChar(smsTmpByte, readByte);
          ++smsBodyPosByte;
          // analize TP-MTI & Co
          smsTPUDHI = bitRead(smsTPMTICO, 6);
          if ((bitRead(smsTPMTICO, 0) == 0) && (bitRead(smsTPMTICO, 1) == 0)) smsStep = 102; else smsStep = 0;
        }
        break;
      }
    case 102: { // get TP-OA - sender
        if (bitRead(smsOriginalPosByte, 0)) {
          smsTmpByte = readByte;
        } else {
          smsSizePhone = getByteFromTwoChar(smsTmpByte, readByte);
          if (bitRead(smsSizePhone, 0)) smsTmpSize = smsSizePhone + 1; else smsTmpSize = smsSizePhone;
          ++smsBodyPosByte;
          smsStep = 103;
        }
        break;
      }
    case 103: { // get TP-OA - sender
        if (bitRead(smsOriginalPosByte, 0)) {
          smsTmpByte = readByte;
        } else {
          smsTPOA = getByteFromTwoChar(smsTmpByte, readByte);
          ++smsBodyPosByte;
          smsSender[0] = 0;
          smsStep = 104;
        }
        break;
      }
    case 104: { // get TP-OA - sender
        if (bitRead(smsOriginalPosByte, 0)) {
          smsTmpByte = readByte;
        } else {
          ++smsBodyPosByte;
          // processing sender
          byte ts;
          if (bitRead(smsSizePhone, 0)) ts = smsSizePhone + 1; else ts = smsSizePhone;
          byte tp = ts - smsTmpSize;
          if ((bitRead(smsTPOA, 6) == 1) && (bitRead(smsTPOA, 5) == 0) && (bitRead(smsTPOA, 4) == 1) &&
              (bitRead(smsTPOA, 3) == 0) && (bitRead(smsTPOA, 2) == 0) && (bitRead(smsTPOA, 1) == 0) && (bitRead(smsTPOA, 0) == 0)) {
            // char sender
            // ignore sms
            smsStep = 0;
            break;
          } else if ((bitRead(smsTPOA, 6) == 0) && (bitRead(smsTPOA, 5) == 0) && (bitRead(smsTPOA, 4) == 1) &&
                     (bitRead(smsTPOA, 3) == 0) && (bitRead(smsTPOA, 2) == 0) && (bitRead(smsTPOA, 1) == 0) && (bitRead(smsTPOA, 0) == 1)) {
            // number phone
            if (tp < max_size_sms_sender) smsSender[tp] = readByte;
            ++tp;
            if (tp < max_size_sms_sender) smsSender[tp] = smsTmpByte;
            if ((ts > smsSizePhone) && (smsTmpSize <= 2)) {
              if (tp < max_size_sms_sender) smsSender[tp] = 0;
            } else {
              if ((tp + 1) < max_size_sms_sender) smsSender[tp + 1] = 0;
            }
          } else {
            smsStep = 0;
            break;
          }
          // ---
          if ((smsTmpSize -= 2) == 0) smsStep = 105;
        }
        break;
      }
    case 105: { // TP-PID
        if (bitRead(smsOriginalPosByte, 0)) {
          smsTmpByte = readByte;
        } else {
          ++smsBodyPosByte;
          smsStep = 106;
        }
        break;
      }
    case 106: { // TP-DCS
        if (bitRead(smsOriginalPosByte, 0)) {
          smsTmpByte = readByte;
        } else {
          ++smsBodyPosByte;
          smsTPDCS = getByteFromTwoChar(smsTmpByte, readByte);
          smsStep = 107;
          smsTmpSize = 7;
        }
        break;
      }
    case 107: { // TP-SCTS - skip 7 byte
        if (bitRead(smsOriginalPosByte, 0)) {
          smsTmpByte = readByte;
        } else {
          ++smsBodyPosByte;
          if ((--smsTmpSize) == 0) smsStep = 108;
        }
        break;
      }
    case 108: { // TP-UDL
        if (bitRead(smsOriginalPosByte, 0)) {
          smsTmpByte = readByte;
        } else {
          ++smsBodyPosByte;
          smsTmpSize = getByteFromTwoChar(smsTmpByte, readByte);
          if (smsTPUDHI == 0) {
#if (SHOW_SMS == 1)
            Serial.println(smsSender);
#endif
            smsPrevDecodeByte = 0;
            smsIdxCurrentChar = 0;
            smsStep = 109;
          } else {
            // long sms
            smsStep = 110;
          }
        }
        break;
      }
    case 109: { // body sms
        if (bitRead(smsOriginalPosByte, 0)) {
          smsTmpByte = readByte;
        } else {
          byte tb = getByteFromTwoChar(smsTmpByte, readByte);
          if (smsTPDCS == 0) {
            // decode 7 bit
            getDecode7bitChar(smsPrevDecodeByte, tb);
            smsPrevDecodeByte = tb;
          } else {
            // decode UCS2
            if ((smsPrevDecodeByte == 0x04) && (tb >= 0x10) && (tb <= 0x4F)) {
              // rus unicode
#if (SHOW_SMS == 1)
              if (tb >= 0x40) {
                Serial.write(0xD1);
                Serial.write(0x40 + tb);
              } else {
                Serial.write(0xD0);
                Serial.write(0x80 + tb);
              }
#endif
            } else if ((smsPrevDecodeByte == 0x04) && (tb == 0x01)) {
#if (SHOW_SMS == 1)
              Serial.write(0xD0); Serial.write(0x01);
#endif
            } else if ((smsPrevDecodeByte == 0x04) && (tb == 0x51)) {
#if (SHOW_SMS == 1)
              Serial.write(0xD1); Serial.write(0x91);
#endif
            } else if ((smsPrevDecodeByte == 0x00) && (tb >= 0x20) && (tb < 0x7F)) {
              // ascii
#if (SHOW_SMS == 1)
              Serial.write(tb);
#endif
              // find external command
              byte bc = findCmdInBuf(tb);
              if (bc) execExtCmd(bc - 1);
            }
            smsPrevDecodeByte = tb;
          }
          if ((++smsBodyPosByte) >= smsOriginalSize) {
            // end sms
            smsStep = 0;
#if (SHOW_SMS == 1)
            if (smsTPUDHI == 0) {
              Serial.write('\r');
              Serial.write('\n');
            } else if (smsIED = smsIEDL) {
              Serial.write('\r');
              Serial.write('\n');
            }
#endif
          }
        }
        break;
      }
    case 110: { // TP-UDH
        if (bitRead(smsOriginalPosByte, 0)) {
          smsTmpByte = readByte;
        } else {
          ++smsBodyPosByte;
          // get num and count sms and show sender
          smsUDHL = getByteFromTwoChar(smsTmpByte, readByte) - 1;
          smsStep = 111;
        }
        break;
      }
    case 111: { // EIDL
        if (bitRead(smsOriginalPosByte, 0)) {
          smsTmpByte = readByte;
        } else {
          ++smsBodyPosByte;
          // get num and count sms and show sender
          if ((--smsUDHL) == 0) {
            smsIEDL = getByteFromTwoChar(smsTmpByte, readByte);
            smsStep = 112;
          }
        }
        break;
      }
    case 112: { // EID
        if (bitRead(smsOriginalPosByte, 0)) {
          smsTmpByte = readByte;
        } else {
          ++smsBodyPosByte;
          // get num and count sms and show sender
          smsIED = getByteFromTwoChar(smsTmpByte, readByte);
#if (SHOW_SMS == 1)
          if (smsIED == 1) Serial.println(smsSender);
#endif
          smsPrevDecodeByte = 0;
          smsIdxCurrentChar = 6;
          smsStep = 109;
        }
        break;
      }
    default: {}
  }
}

void smsClearOut() {
  sms_buf[0] = 0;
  sms_out_size_packet = 0;
}

void smsPrepareSender(char* textSender) {
  strcpy(smsSender, textSender);
}

void smsPrepareText(char* textText) {
  if ((strlen(sms_buf) + strlen(textText)) < (max_size_out_sms - 1)) strcat(sms_buf, textText);
}

void smsPrepareText(byte inByte) {
  byte st = strlen(sms_buf);
  if (st < (max_size_out_sms - 1)) {
    sms_buf[st] = inByte;
    sms_buf[st + 1] = 0;
  }
}

void smsPrepareOut() {
  sms_out_pos_sender = 0;
  sms_out_pos_string = 0;
  sms_out_pos_other = 0;
  sms_out_pos_mode = 0;
  // calculate size all fields SMS by PDU format
  sms_out_size_packet = 3; // SCA + PDU Type + MR
  smsLenSender = strlen(smsSender);
  byte lenSender = smsLenSender;
  if (bitRead(lenSender, 0)) ++lenSender;
  sms_out_size_packet += 2; // lenght + format sender
  sms_out_size_packet += (lenSender / 2); // sender
  sms_out_size_packet += 3; // PID + DCS + VP(null) +UDL
  smsLenString = strlen(sms_buf);
  smsUDL = (smsLenString * 2);
  sms_out_size_packet += smsUDL; // UD
  --sms_out_size_packet; // -SCA
}

byte smsOutPackedByte() {
  switch (sms_out_pos_mode) {
    case 0: { // SCA
        if (sms_out_pos_other) {
          ++sms_out_pos_mode;
          sms_out_pos_other = 0;
          return '0';
        } else {
          ++sms_out_pos_other;
          return '0';
        }
        break;
      }
    case 1: { // PDU Type
        if (sms_out_pos_other) {
          ++sms_out_pos_mode;
          sms_out_pos_other = 0;
          return '1';
        } else {
          ++sms_out_pos_other;
          return '0';
        }
        break;
      }
    case 2: { // MR
        if (sms_out_pos_other) {
          ++sms_out_pos_mode;
          sms_out_pos_other = 0;
          return '0';
        } else {
          ++sms_out_pos_other;
          return '0';
        }
        break;
      }
    case 3: { // DA
        if (sms_out_pos_other < 2) { // lenght sender
          // lenth to HEX
          if (sms_out_pos_other) {
            ++sms_out_pos_other;
            byte tb = (smsLenSender % 16);
            if (tb > 9) return (tb + 0x37); else return (tb + '0');
          } else {
            ++sms_out_pos_other;
            return ((smsLenSender / 16) + '0');
          }
        } else if (sms_out_pos_other < 4) { // format sender = 91
          if (sms_out_pos_other == 2) {
            ++sms_out_pos_other;
            return '9';
          } else {
            ++sms_out_pos_other;
            return '1';
          }
        } else { // sender
          if (sms_out_pos_sender < smsLenSender) {
            ++sms_out_pos_other; ++sms_out_pos_sender;
            if (bitRead(sms_out_pos_sender, 0)) {
              if ((sms_out_pos_sender >= smsLenSender) && (bitRead(smsLenSender, 0)))
                return ('F'); else
                return (smsSender[sms_out_pos_sender]);
            }  else  {
              return (smsSender[sms_out_pos_sender - 2]);
            }
          } else {
            sms_out_pos_other = 0; ++sms_out_pos_mode;
            if (bitRead(smsLenSender, 0))
              return (smsSender[smsLenSender - 1]);
            else return 0xFF;
          }
        }
        break;
      }
    case 4: { // PID
        if (sms_out_pos_other) {
          ++sms_out_pos_mode;
          sms_out_pos_other = 0;
          return '0';
        } else {
          ++sms_out_pos_other;
          return '0';
        }
        break;
      }
    case 5: { // DCS
        if (sms_out_pos_other) {
          ++sms_out_pos_mode;
          sms_out_pos_other = 0;
          return '8';
        } else {
          ++sms_out_pos_other;
          return '0';
        }
        break;
      }
    case 6: { // UDL
        if (sms_out_pos_other) {
          ++sms_out_pos_mode;
          sms_out_pos_other = 0;
          byte uh = smsUDL % 16;
          if (uh > 9) return (uh + 0x37); else return (uh + '0');
        } else {
          ++sms_out_pos_other;
          byte uh = smsUDL / 16;
          if (uh > 9) return (uh + 0x37); else return (uh + '0');
        }
        break;
      }
    case 7: { // UD
        if (sms_out_pos_string < smsLenString) {
          byte outChar = sms_buf[sms_out_pos_string];
          byte bpos = (sms_out_pos_other % 4);
          switch (bpos) {
            case 0: {
                ++sms_out_pos_other;
                return '0';
                break;
              }
            case 1: {
                ++sms_out_pos_other;
                if (outChar < 0x7F) return '0'; else return '4';
                break;
              }
            case 2: {
                ++sms_out_pos_other;
                if (outChar < 0x7F) {
                  // ascii
                  outChar = (outChar / 16);
                  if (outChar > 9) return (outChar + 0x37); else return (outChar + '0');
                } else {
                  // win1251
                  switch (outChar) {
                    case 168: {
                        return '0'; break;
                      }
                    case 184: {
                        return '5'; break;
                      }
                    default: {
                        outChar -= 0xB0;
                        outChar = (outChar / 16);
                        if (outChar > 9) return (outChar + 0x37); else return (outChar + '0');
                      }
                  }
                }
                break;
              }
            case 3: {
                ++sms_out_pos_other;
                ++sms_out_pos_string;
                if (outChar < 0x7F) {
                  // ascii
                  outChar = (outChar % 16);
                  if (outChar > 9) return (outChar + 0x37); else return (outChar + '0');
                } else {
                  // win1251
                  switch (outChar) {
                    case 168: {
                        return '1'; break;
                      }
                    case 184: {
                        return '1'; break;
                      }
                    default: {
                        outChar -= 0xB0;
                        outChar = (outChar % 16);
                        if (outChar > 9) return (outChar + 0x37); else return (outChar + '0');
                      }
                  }
                }
                break;
              }
            default: {}
          }
        } else {
          ++sms_out_pos_mode;
          sms_out_pos_other = 0;
          return 0; // 0xFF for next step
        }
        break;
      }
    default: {
        return 0;
      };
  }
}

byte smsGetSizePDU() {
  return sms_out_size_packet;
}

byte doHaveSendSms() {
  if ((sms_buf[0] > 0) && (sms_out_size_packet) && (smsSender[0] > 0)) return 1; else return 0;
}

Скетч использует 15484 байт (50%) памяти устройства. Всего доступно 30720 байт.
Глобальные переменные используют 1042 байт (50%) динамической памяти, оставляя 1006 байт для локальных переменных. Максимум: 2048 байт.

 

traveler
Offline
Зарегистрирован: 27.09.2018

andycat пишет:

как и обещал, часть скетча (4 файла из 5), вдруг пригодится:


Скетч использует 15484 байт (50%) памяти устройства. Всего доступно 30720 байт.
Глобальные переменные используют 1042 байт (50%) динамической памяти, оставляя 1006 байт для локальных переменных. Максимум: 2048 байт.

 

Спасибо! Такое большое количество команд мне не потребуется для решения моей задачи, все равно - спасибо! Но, опять же, у Вас в коде задется все путем, описанным в ссылках по работе с PGM. У меня же, задается путем объявления структуры, а затем уже записью значений переменных структуры массивов в Flash-память МК.

Со сравнением, с общей помощью разобрался, остался вопрос, как поместить содержимое из Flash-памяти в динамическую память, присвоив значение переменной из Flash-памяти переменной в динамическую память... Код не работает:



#include <avr/pgmspace.h>

const uint8_t cntLstPhones = 2;

struct listUsr_t
{
  const char phoneNum[13];
  const char phonePass[5];
  const char phonePDU[13];
  const char plot[9];
};
 
const listUsr_t PROGMEM users[cntLstPhones] =
{
  { "+78881890123", "0000", "000000000000", "plot #" },
  { "+78881901234", "0000", "000000000000", "plot #" }
};


void setup()
{
Serial.begin(9600);


char val[13];
strcat_P(val, pgm_read_word(&(users[1].phoneNum)));
Serial.println(val);
}

 

Модет кто-то подскажет, что не так я делаю...

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

мошт, надо strсpy_P  использывать, а не strcat?   (Но это неточно)

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

traveler  , мне кажеться вам нужно на классы переходить, в PGM харнить все списками, т.е. телефоны отдельный список, ПИН коды отдельным и т.д. Соотвественно когда в экземпляре класса необходимы данные непосредственно из progmem - динамически вытаскивать оттуда данные.

P.S. Классы не люблю, дело вкуса, но в вашей задаче вообще бы не использовал ни классы ни структуры, 4 функции по вытаскиванию данных из pgm и все.

traveler
Offline
Зарегистрирован: 27.09.2018

DetSimen пишет:

мошт, надо strсpy_P  использывать, а не strcat?   (Но это неточно)

Я и strcpy_P и strcat_P - пытался использовать... не работает код и все...

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

traveler пишет:

DetSimen пишет:

мошт, надо strсpy_P  использывать, а не strcat?   (Но это неточно)

Я и strcpy_P и strcat_P - пытался использовать... не работает код и все...

наверное что то вы недопонимаете......

и образец вам кинули, и литературы много....

http://arduino.ru/forum/programmirovanie/ocherednoi-raz-progmem#comment-...

 

traveler
Offline
Зарегистрирован: 27.09.2018

andycat пишет:

наверное что то вы недопонимаете......

и образец вам кинули, и литературы много....

http://arduino.ru/forum/programmirovanie/ocherednoi-raz-progmem#comment-...

Ещё раз повторюсь, я хотел использовать структуру, все ссылки и вся литература описывает без структур... Мне нужна просто подсказка, вернее, правильный синтаксис строки, которая считает переменную из Flash в RAM, все... Сравнить переменные из Flash с переменными из RAM, уже знаю как, а как "вытащить" переменную из Flash и записать ее в локальную переменную функции в RAM - не знаю, поэтому мне нужна просто подсказка с синтаксисом оператора, который позволит выполнить такой перенос...

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

traveler пишет:

andycat пишет:

наверное что то вы недопонимаете......

и образец вам кинули, и литературы много....

http://arduino.ru/forum/programmirovanie/ocherednoi-raz-progmem#comment-...

Ещё раз повторюсь, я хотел использовать структуру, все ссылки и вся литература описывает без структур... Мне нужна просто подсказка, вернее, правильный синтаксис строки, которая считает переменную из Flash в RAM, все... Сравнить переменные из Flash с переменными из RAM, уже знаю как, а как "вытащить" переменную из Flash и записать ее в локальную переменную функции в RAM - не знаю, поэтому мне нужна просто подсказка с синтаксисом оператора, который позволит выполнить такой перенос...

Т е ссылка которую я дал - там примера чтения в ram вы не увидели?
А хранить в структуре адрес на строку в pgm вы тоже не догадались?
:(

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

traveler пишет:

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

"подсказок" правильного синтаксиса извлечения строк из флеша тут уже дали не одну и не две...

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

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

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

посмотрел выше - в сообщ #22 sadman41 давал вам пример сравнения строки из флеша и оперативки. Посмотрите внимательно - как у него сделано обращение к полю вашей структуры и как у вас. Сравните внимательно! - у вас там ошибка

Хотя.. все равно же не найдете.Ладно, подскажу - когда вы обращаетесь к своей строке во флеше, вы непонятно зачем выполняете операцию взятия адреса & от массива.  Причем вы так делали еще в самом начале ветки и я вас уже поправлял. Поймите - имя массива это и так адрес его первого элемента, а когда вы еще ставите перед ним & - получается "адрес от адреса" - что ерунда.

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

traveler
Offline
Зарегистрирован: 27.09.2018

andycat пишет:
Т е ссылка которую я дал - там примера чтения в ram вы не увидели? А хранить в структуре адрес на строку в pgm вы тоже не догадались? :(

Конечно, же, увидел, НО, в примере, который Вы предложили, как раз таки нет структуры...

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

Честно говоря, я не понимаю, как в структуру "запихнуть" адрес на строку, да и зачем, если сравнить можно и с той структурой, что имеется, то почему нельзя перенести из Flash в RAM...

traveler
Offline
Зарегистрирован: 27.09.2018

b707 пишет:

посмотрел выше - в сообщ #22 sadman41 давал вам пример сравнения строки из флеша и оперативки. Посмотрите внимательно - как у него сделано обращение к полю вашей структуры и как у вас. Сравните внимательно! - у вас там ошибка

Хотя.. все равно же не найдете.Ладно, подскажу - когда вы обращаетесь к своей строке во флеше, вы непонятно зачем выполняете операцию взятия адреса & от массива.  Причем вы так делали еще в самом начале ветки и я вас уже поправлял. Поймите - имя массива это и так адрес его первого элемента, а когда вы еще ставите перед ним & - получается "адрес от адреса" - что ерунда.

Я постараюсь сейчас разобраться с указателем...

b707 пишет:

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

Просто нет на это времени, я ведь не с целью продажи или какого-то бизнеса, просто для себя, для удобства хочу собрать устройство для управления воротами... Как хобби, если хотите... Со временем - разберусь с азов, сейчас времени нет, если появиться время,  с азов разберусь... 

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

traveler пишет:

 к сожалению... времени на изучения с нуля, тоже нет...

простите, но после таких заявлений здесь обычно посылают - жестко, матом - и общение заканчивается. Это что за наглость - у вас, видите ли, нет времени это изучать - а у нас. выходит, куча времени чтобы обьяснять вам одно и тоже по 3-4 раза?

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

 

traveler
Offline
Зарегистрирован: 27.09.2018

Такой код, также не работает...

char val[] = "";
strcpy_P(val, pgm_read_word(users[19].phoneNum));
Serial.println(val);

 

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

traveler пишет:

Такой код, также не работает...

char val[] = "";
strcpy_P(val, pgm_read_word(users[19].phoneNum));
Serial.println(val);

 

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

traveler
Offline
Зарегистрирован: 27.09.2018

Вот такой код, возвращает знаки, но не строку...

char val[13];
strncpy_P(val, pgm_read_word(users[1].phoneNum), 13);
Serial.println(val);

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

traveler пишет:

Такой код, также не работает...

char val[] = "";
strcpy_P(val, pgm_read_word(users[19].phoneNum));
Serial.println(val);

 

вы похоже, втупую пробуете разные комбинации операторов... опять val описано неправильно.

Так вы программу не напишете. Садитесь за учебники - ваши ворота подождут.  Тем более если это хобби, как вы пишете - значит просто сделаете ворота не сейчас. а через полгода-год, когда разберетесь.

sadman41
Offline
Зарегистрирован: 19.10.2016

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

#include <avr/pgmspace.h>

  struct listUsr_t
  {
  const char phoneNum[13];
  const char phonePass[5];
  const char phonePDU[13];
  };

  const listUsr_t PROGMEM users[] =
  {
  { "70000000000", "00000", "000000000000"},
  { "70000000001", "00001", "000000000000"},
  { "70000000002", "00002", "000000000000"},
  };

void setup() {
  char incomingNumber[20];
  Serial.begin(115200);
  Serial.println("Begin!");

  for (int i = 0; i < 3; i++) {
    strncpy_P(incomingNumber, (char*) users[i].phoneNum, sizeof(listUsr_t::phoneNum));
    Serial.println(incomingNumber);
  }
}

void loop() {
  // put your main code here, to run repeatedly:
}

И еще я не совсем уверен, что sizeof можно напускать на такого жука... Ну, если что - поправят. 

Почему-то в данном примере помещение строковых констант прямо в массив эквивалентно помещению в массив ссылок на строковые константы (как на arduino.cc), но попытка перетащить данный пример в реальный скетч почему-то дает разные результаты по компиляции. Надо будет этот вопрос изучить. Может компилятор умничает опять.

char val[] = ""  - это чего, зарезервировали нуль байт памяти, а потом туда строку копируете? Вы там надеюсь, игрушку-пердушку собираете, а не управление газовым котлом...

traveler
Offline
Зарегистрирован: 27.09.2018

b707 пишет:

вы похоже, втупую пробуете разные комбинации операторов... опять val описано неправильно.

Так вы программу не напишете. Садитесь за учебники - ваши ворота подождут.  Тем более если это хобби, как вы пишете - значит просто сделаете ворота не сейчас. а через полгода-год, когда разберетесь.

тут переписал не правильно, указал длину...