Raspberry Pi Pico

rkit
Offline
Зарегистрирован: 23.11.2016

В ошибке даже стрелочка нарисована, откуда берет.

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

хм, 

((p3) << 22) | ((p3) << 27))

оно?

ок, спасибо, пошел искать путь к этим переменным....

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Интересный модуль...и по цене и по возможностям...

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

Самое приятное, с моей точки зрения:простота работы с периферией по сравнению с stm32 cmsis. Sdk хорОш!

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

andycat пишет:
Самое приятное, с моей точки зрения:простота работы с периферией по сравнению с stm32 cmsis. Sdk хорОш!

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

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

andycat пишет:
Самое приятное, с моей точки зрения:простота работы!

простота =  она же беднота.... Режимов таймера с гулькин нос

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

Для каждой задачи нужен свой МК, нужны таймеры - берём stm32.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

andycat пишет:
Для каждой задачи нужен свой МК, нужны таймеры - берём stm32.

отож!!! STM32WB55VG c памятью побольше )))

Чтобы было информативно, закину определения для PWM
 


#define pin0   0    // PWM channel 0A
#define pin1   1    // PWM channel 0B
#define pin2   2    // PWM channel 1A
#define pin3   3    // PWM channel 1B
#define pin4   4    // PWM channel 2A
#define pin5   5    // PWM channel 2B
#define pin6   6    // PWM channel 3A
#define pin7   7    // PWM channel 3B
#define pin8   8    // PWM channel 4A
#define pin9   9    // PWM channel 4B
#define pin10 10    // PWM channel 5A
#define pin11 11    // PWM channel 5B
#define pin12 12    // PWM channel 6A
#define pin13 13    // PWM channel 6B
#define pin14 14    // PWM channel 7A
#define pin15 15    // PWM channel 7B
#define pin16 16    // PWM channel 0A
#define pin17 17    // PWM channel 0B
#define pin18 18    // PWM channel 1A
#define pin19 19    // PWM channel 1B
#define pin20 20    // PWM channel 2A
#define pin21 21    // PWM channel 2B
#define pin22 22    // PWM channel 3A
#define pin23 23    // PWM channel 3B
#define pin24 24    // PWM channel 4A
#define pin25 25    // PWM channel 4B
#define pin26 26    // PWM channel 5A
#define pin27 27    // PWM channel 5B
#define pin28 28    // PWM channel 6A
#define pin29 29    // PWM channel 6B

 

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

Если кто обратил внимание, предделители у таймеров Пики имеют тип float. То есть, вроде как можно подстраивать частоту плавно :) Давно меня занимала эта фича, только не на чем было проверить. А тут наконец приехал мне с Али логиканализатор на 100 МГц. Настроил PWM, макс значение счета 5 - соответственно частота должна получится 133 / 5 = 26.6 МГц. Установил предделитель 1.064, чтобы, значит, получить на выходе ровно 25 МГц

26.6 / 1.064 = 25 МГц

Чуда не произошло. Как я и предполагал, частота не настраивается плавно. 25 МГц из 26 делается примерно так - десяток импульсов на частоте 26.6 и один на частоте 20. Потом снова десяток на 26....

Может я что не так настроил - попробуйте сами.

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

Ну так millis() в AVR так же работает. И 55-мс прерывания в DOS-сессии Windows - тоже.

25 МГц - это значит, 25000000 импульсов в секунду. Разве нет?

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

andriano пишет:

Ну так millis() в AVR так же работает. И 55-мс прерывания в DOS-сессии Windows - тоже.

25 МГц - это значит, 25000000 импульсов в секунду. Разве нет?

улыбнул значит )))

Да, есть проблема, объединил скетчи сканера wifi и двухтонального генератора и,
(выход синхронизации работает как и положено на 225 герц
а вот выход частоты 1800 пропускает импульсы, попробую перевести на другой пин...


 

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ничего не дало, на другом пине также пропускает

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

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

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

ua6em пишет:

делители float бывают только в сказках...

читаем даташит и описание SDK внимательно....

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

andriano пишет:

25 МГц - это значит, 25000000 импульсов в секунду. Разве нет?

это как посмотреть :)

Можно сказать и так - "частота 25 МГц это означает что импульсы идут через каждые 1/ 25 000 000 секунды".... и тут уже будут нюансы

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

b707 пишет:

ua6em пишет:

делители float бывают только в сказках...

читаем даташит и описание SDK внимательно....

я жеж безграмотный, поговорить куда ни шло )))

Если оставить только два PWM то всё работает как надо и 1800 и 2250 ...

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ребята, если чё, так Вы работаете с цифровой техникой, не забыли?

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

Ребята, если чё, так Вы работаете с цифровой техникой, не забыли?

ясный пень аналоговнет

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

ЕвгенийП пишет:

Ребята, если чё, так Вы работаете с цифровой техникой, не забыли?

а вдруг? :)

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

b707 пишет:

andriano пишет:

25 МГц - это значит, 25000000 импульсов в секунду. Разве нет?

это как посмотреть :)

Можно сказать и так - "частота 25 МГц это означает что импульсы идут через каждые 1/ 25 000 000 секунды".... и тут уже будут нюансы

Из первого второе никак не следует. Если бы вдруг следовало, такого понятия как джиттер не существовало бы.

И, кстати, Петрович выше справедливо заметил, что мы имеем дело с цифрой, а потому 25000000 импульсов в секунду и никаких дополнительных условий.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

признавайтесь, кто SPI исследовал?
Не могу разобраться с установкой скорости в библиотеке Adafruit - не устанавливается.
SPI тянет от hardwarespi.h, там она по умолчанию 4 мегагерца, но при применении библиотеки Adafruit_ST7735 она явно сильно ниже
По осциллограмме ниже видно, что обмен идёт в 16 битном режиме на скорости 50 килогерц?
Откуда это берётся???

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

Для w5500 ставил 1 МГц, не работало, пришлось прицепить логанализатор, реально spi 1мгц было. Большую частоту не пробовал.
И при чем тут скорость передачи данных? Смотрим частоту clk пина spi, по нему и судим о скорости.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

CLK на осциллограмме зелёный луч

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

Ну, если я правильно вижу, в ячейке 5 мксек, два импульса в ячейке, аккурат 4мгц, не?

Upd: не,
Или 200 ns это ширина квадратика?

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

andycat пишет:
Ну, если я правильно вижу, в ячейке 5 мксек, два импульса в ячейке, аккурат 4мгц, не? Upd: не, Или 200 ns это ширина квадратика?

частота по символу H, что такое D пока не знаю (может время нарастания-спада сигнала), особо осциллограф не изучал, выставил исследование SPI и смотрю, обрабатывает не быстро иногда висит висит но так на экран ничего и не выведет, короче это не ригол )))

4 мегагерца это 250 наносекунд, 1 мегагерц - 1 микросекунда это у меня въелось )))

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

Получается период (грубо) 2.5 мкс, значит частота 400 кГц, библиотека врет, используем sdk и прямое общение с устройством, и наступит счастье)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

andycat пишет:
Получается период (грубо) 2.5 мкс, значит частота 400 кГц, библиотека врет, используем sdk и прямое общение с устройством, и наступит счастье)

так не бывает, где-то однозначно должно это устанавливаться, пока не нашёл где...

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

Работа с модемом SIM800L
Инициализация + чтение SMS в PDU формате, в том числе составных.
Пока только в 7и битной кодировке (латиница), кириллица позже будет.

#ifndef SIM800_PICO_H
#define SIM800_PICO_H

/// modem SIM800L UART
#define UART_ID uart0
#define BAUD_RATE 9600
#define DATA_BITS 8
#define STOP_BITS 1
#define PARITY    UART_PARITY_NONE
// We are using pins 12 and 13, but see the GPIO function select table in the
// datasheet for information on which other pins can be used.
#define UART_TX_PIN 12
#define UART_RX_PIN 13
#define pinResetModem 23 // пин сброса модема

#define max_size_modem_rx_buf 2048 // приемный буфер данных от модема
#define period_wait_start_modem 15000UL // время ожидания модема после включения
#define period_wait_registration 120000UL // время ожидания регистрации модема в сети оператора
#define period_read_sms 10000UL // как часто с модема читать СМС

enum tModemGlobalStatus {modemStBegin = 0, modemStInit, modemStReg, modemStReboot, modemStReady};

void modemInit(void); // инициализируем пины
void modemReset(void); // сброс модема
void modemMainLoop(void);

union t_TP_MTIandCo {
    struct {
        unsigned TP_MTI:2;
        unsigned TP_MMS:1;
        unsigned res1:1;
        unsigned res2:1;
        unsigned TP_SRI:1;
        unsigned TP_UDHI:1;
        unsigned TP_RP:1;
    };
    unsigned char TP_MTI_Value;
};
 

#endif  /* SIM800_PICO_H */


#include <stdio.h>
#include "pico/stdlib.h"
#include "sim800pico.h"
#include "millpico.h"
#include <string.h>
#include <ctype.h>

tModemGlobalStatus currentGlobalStatusModem = modemStBegin;

unsigned char modemRXbuf[max_size_modem_rx_buf];
unsigned short modemPosBuf;
unsigned char modemStepWork;
unsigned long modemTimerWork = 0UL;
unsigned char operatorName[16];
unsigned char operatorCSQ;

signed short findPosSubstringFromBuf(unsigned char * inStr) {
    char * pStr = strstr((const char *) modemRXbuf, (const char *) inStr);
    if (pStr) return (inStr - ((unsigned char*)pStr));
    else return -1;
}

bool findOKRNfromBuf(void) {
    if (findPosSubstringFromBuf((unsigned char *)"OK\r\n") >= 0) return true;
    else return false;
}

void initModemUART(void) {  // sim800 uart init
    // Set up our UART with the required speed.
    uart_init(UART_ID, BAUD_RATE);
    // Set the TX and RX pins by using the function select on the GPIO
    // Set datasheet for more information on function select
    gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);
    gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);
    // Use some the various UART functions to send out data
    // In a default system, printf will also output via the default UART
    // Send out a character without any conversions
    //uart_putc_raw(UART_ID, 'A');
    // Send out a character but do CR/LF conversions
    //uart_putc(UART_ID, 'B');
    // Send out a string, with CR/LF conversions
    //uart_puts(UART_ID, " Hello, UART!\n");
    // Actually, we want a different speed
    // The call will return the actual baud rate selected, which will be as close as
    // possible to that requested
    int __unused actual = uart_set_baudrate(UART_ID, BAUD_RATE);
    // Set UART flow control CTS/RTS, we don't want these, so turn them off
    uart_set_hw_flow(UART_ID, true, true);
    // Set our data format
    uart_set_format(UART_ID, DATA_BITS, STOP_BITS, PARITY);
    // Turn off FIFO's - we want to do this character by character
    uart_set_fifo_enabled(UART_ID, true);
}

void modemInit(void) {  // инициализируем пины и все остальное
    gpio_init(pinResetModem); // sim800 reset
    gpio_set_dir(pinResetModem, GPIO_IN); // sim800 reset
    gpio_put(pinResetModem, 0); // sim800 reset
    initModemUART(); // sim800 uart init
}

void modemReset(void) { // сброс модема
    gpio_set_dir(pinResetModem, GPIO_OUT);
    sleep_ms(115);
    gpio_set_dir(pinResetModem, GPIO_IN);
}

void modemClearRXbuf(void) {
    modemPosBuf = 0;
    memset(modemRXbuf, '\0', max_size_modem_rx_buf);
    //modemRXbuf[modemPosBuf] = '\0';
}

void modemSendCMDandShowAndTimerStep(unsigned char * inStr) {
    uart_puts(UART_ID, (const char*)inStr);
    printf("%s\n", inStr);
    modemTimerWork = millis(); // сбросим таймер
    ++modemStepWork; // На след шаг
}

bool processCREG(void) { // парсинг ответа модема на команду AT+CREG
    char * p1 = strstr((const char *) modemRXbuf, (const char *) "+CREG: ");
    if (p1) {
        if (p1 >= ((const char *) modemRXbuf)) {
            char * p2 = strchr((const char *) modemRXbuf, ',');
            if (p2) {
                if (p2 > p1) {
                    unsigned char br = *(p2+1);
                    if ((br == '1') || (br == '5')) return true;
                }
            }
        }
    }
    return false;
}

void processCOPS(void) { // парсинг ответа модема на команду AT+COPS
    char * p1 = strstr((const char *) modemRXbuf, (const char *) "+COPS: ");
    if (p1) {
        if (p1 >= ((const char *) modemRXbuf)) {
            char * p2 = strchr((const char *) modemRXbuf, ',');
            if (p2) {
                char * p3 = strchr((p2+1), ',');
                if (p3) {
                    if ((p3>p2) && ((*(p3+1)) == '"')) {
                        char * p4 = strchr((p3+2), '"');
                        if ((p4) && (p4>(p3+2))) {
                            unsigned char lenP = p4-p3-2;
                            for (unsigned char i=0; i<lenP; ++i) operatorName[i] = *(p3+2+i);
                            operatorName[lenP] = '\0';
                        }
                    }
                }
            }
        }
    }
}

void processCSQ(void) { // парсинг ответа модема на команду AT+CSQ
    char * p1 = strstr((const char *) modemRXbuf, (const char *) "+CSQ: ");
    if (p1) {
        if (p1 >= ((const char *) modemRXbuf)) {
            if (isdigit(*(p1+6))) {
                unsigned char tC = (*(p1+6)) - '0';
                if (isdigit(*(p1+7))) {
                    operatorCSQ = tC*10+((*(p1+7)) - '0');
                } else {
                    operatorCSQ = tC;
                }
            }
        }
    }
}

bool modemCMDstReg(bool inLine) {
    static unsigned long timerRegistration;
    static bool goodCREG;
    switch (modemStepWork) {
        case 0: {
            timerRegistration = millis();
            goodCREG = false;
            ++modemStepWork;
            break;
        }
        case 1: {
            modemSendCMDandShowAndTimerStep((unsigned char *)"AT+CREG?\r"); // проверяем зарегестрировался ли модем в сети
            break;
        }
        case 2: {
            if ((millis() - timerRegistration) >= period_wait_registration) return false;
            if ((millis() - modemTimerWork) >= 5000UL) { // больше 5 сек нет ответа
                modemTimerWork = millis(); // сбросим таймер
                modemStepWork = 25; // перейдем на паузу 5 секунд, что бы потом опять запросить статус регистрации
            } else {
                if (inLine) { // если пришла строка
                    if (processCREG()) goodCREG = true; // парсим строку - если зарегестрировались - ставим флаг
                    if (findOKRNfromBuf()) { // ищем ответ ОК
                        if (goodCREG) { // если успешно зарегестрировались
                            modemSendCMDandShowAndTimerStep((unsigned char *)"AT+COPS?\r"); // получить режим подключения к оператору и имя оператора
                            operatorName[0] = 0; // очищаем имя оператора
                        } else { // если так и не смогли зарегестрироваться
                            modemTimerWork = millis(); // сбросим таймер
                            modemStepWork = 25; // перейдем на паузу 5 секунд, что бы потом опять запросить статус регистрации
                        }
                    }
                }
            }
            break;
        }
        case 3: {
            if ((millis() - modemTimerWork) >= 5000UL) return false;
            if (inLine) { // если пришла строка
                processCOPS();
                if (findOKRNfromBuf()) {
                    modemSendCMDandShowAndTimerStep((unsigned char *)"AT+CSQ\r"); // запрос качества связи
                    operatorCSQ = 0;
                }
            }
            break;
        }
        case 4: {
            if ((millis() - modemTimerWork) >= 5000UL) return false;
            if (inLine) { // если пришла строка
                processCSQ();
                if (findOKRNfromBuf()) modemSendCMDandShowAndTimerStep((unsigned char *)"AT+CMGF=0\r"); // SMS в PDU формате
            }
            break;
        }
        case 5: {
            if ((millis() - modemTimerWork) >= 5000UL) return false;
            if (inLine && findOKRNfromBuf()) { // успешно закончили начальную инициализацию модема
                currentGlobalStatusModem = modemStReady;
                modemStepWork = 0;
            }
            break;
        }
        case 25: {
            if ((millis() - modemTimerWork) >= 5000UL) modemStepWork = 1; // прождали и опять вернулись на запрос регистрации
            break;
        }
        default: {}
    }
    return true;
}

bool modemCMDstInit(bool inLine) {
    switch (modemStepWork) {
        case 0: { // ждем пока модем прочухается
            if ((millis() - modemTimerWork) >= period_wait_start_modem) ++modemStepWork; // На след шаг
            break;
        }
        case 1: {
            modemSendCMDandShowAndTimerStep((unsigned char *)"ATZ\r"); // проверка связи с модемом AT / сброс настроек на default - ATZ
            break;
        }
        case 2: {
            if ((millis() - modemTimerWork) >= 5000UL) return false;
            if (inLine && findOKRNfromBuf()) modemSendCMDandShowAndTimerStep((unsigned char *)"ATE0\r"); // отключение(ATE0) ЭХО, т е модем в обратку не дублирует
            break;
        }
        case 3: {
            if ((millis() - modemTimerWork) >= 5000UL) return false;
            if (inLine && findOKRNfromBuf()) modemSendCMDandShowAndTimerStep((unsigned char *)"ATV1\r"); // развернуты подробный ответ от модема
            break;
        }
        case 4: {
            if ((millis() - modemTimerWork) >= 5000UL) return false;
            if (inLine && findOKRNfromBuf()) modemSendCMDandShowAndTimerStep((unsigned char *)"AT+CMEE=2\r"); // вывод подробных описаний ошибок
            break;
        }
        case 5: {
            if ((millis() - modemTimerWork) >= 5000UL) return false;
            if (inLine && findOKRNfromBuf()) modemSendCMDandShowAndTimerStep((unsigned char *)"AT+CLIP=0\r"); // отключение АОН
            break;
        }
        case 6: {
            if ((millis() - modemTimerWork) >= 5000UL) return false;
            if (inLine && findOKRNfromBuf()) modemSendCMDandShowAndTimerStep((unsigned char *)"ATS0=0\r"); // модем не берет трубку при входящем звонке
            break;
        }
        case 7: {
            if ((millis() - modemTimerWork) >= 5000UL) return false;
            if (inLine && findOKRNfromBuf()) modemSendCMDandShowAndTimerStep((unsigned char *)"AT+CSCLK=0\r"); // отключение работы энергосберегающего режима через пин DTR
            break;
        }
        case 8: {
            if ((millis() - modemTimerWork) >= 5000UL) return false;
            if (inLine && findOKRNfromBuf()) { // закончилась начальная инициализация
                modemStepWork = 0;
                currentGlobalStatusModem = modemStReg; // переходим в режим регистрации оператора
            }
            break;
        }
        default: {}
    }
    return true;
}

enum tSMSmode {smsStNone = 0, smsStGetList, smsStProcessing};

unsigned char smsGetByteFromTwoChars(char * inChars) {
    unsigned char c1 = *inChars;
    unsigned char outByte;
    if (isdigit(c1)) outByte = c1 - '0'; else outByte = c1 - 55;
    outByte *= 16;
    c1 = *(inChars + 1);
    if (isdigit(c1)) outByte += c1 - '0'; else outByte += c1 - 55;
    return outByte;
}

unsigned char smsTextMsg7bit(char * begStr, char * endStr, char * outBuf, unsigned char msgLen) {
    unsigned char outCharPos = 0; // позиция в выходном массиве
    char * currCharPos = begStr; // указатель на символ откуда берем байт
    unsigned char prevDataByte = 0; // предыдущий входящий байт
    while ((currCharPos < endStr) && (outCharPos < msgLen)) {
        unsigned char inDataByte = smsGetByteFromTwoChars(currCharPos); // входной байт
        currCharPos += 2; // сразу сдвинем указатель на два символа вправо = 1 байт данных
        unsigned char idxCurrByte = outCharPos % 8; // индекс сдвига входящего байта 0...7
        if (idxCurrByte) {
            unsigned char lowBits = prevDataByte >> (8 - idxCurrByte);
            *(outBuf+outCharPos) = ((inDataByte << idxCurrByte) & 0x7F) | lowBits;
            ++outCharPos;
            if (idxCurrByte == 7) {
                *(outBuf+outCharPos) = inDataByte;
                ++outCharPos;
            }
        } else {
            *(outBuf+outCharPos) = inDataByte & 0x7F;
            ++outCharPos;
        }
        prevDataByte = inDataByte; // сохраним для след байта данных
    }
    return outCharPos;
}

unsigned char smsTextMsg7bitWithOffset(char * begStr, char * endStr, char * outBuf, unsigned char msgLen, unsigned short inOffset) {
    char * currCharPos = begStr; // указатель на символ откуда берем байт
    unsigned char changeOutOffset = 0; // байт сдвига выходного буфера
    if (inOffset) { // если первый байт сдвигается
        *(outBuf) = smsGetByteFromTwoChars(currCharPos) >> inOffset; // кладем в выходной буфер со сдвигом
        currCharPos += 2; // сразу сдвинем указатель на два символа вправо = 1 байт данных
        changeOutOffset = 1; // будем на 1 символ больше класть в выходной буфер
    }
    unsigned char outCharPos = 0; // позиция в выходном массиве
    unsigned char prevDataByte = 0; // предыдущий входящий байт
    unsigned char idxCurrByte = 0; // индекс сдвига входящего байта 0...6
    while ((currCharPos < endStr) && ((outCharPos+changeOutOffset) < msgLen)) {
        unsigned char inDataByte = smsGetByteFromTwoChars(currCharPos); // входной байт
        currCharPos += 2; // сразу сдвинем указатель на два символа вправо = 1 байт данных
        if (idxCurrByte) {
            unsigned char lowBits = prevDataByte >> (8 - idxCurrByte);
            *(outBuf+outCharPos+changeOutOffset) = ((inDataByte << idxCurrByte) & 0x7F) | lowBits;
            ++outCharPos;
            if (idxCurrByte == 6) {
                *(outBuf+outCharPos+changeOutOffset) = inDataByte >> 1;
                ++outCharPos;
            }
        } else {
            *(outBuf+outCharPos+changeOutOffset) = inDataByte & 0x7F;
            ++outCharPos;
        }
        prevDataByte = inDataByte; // сохраним для след байта данных
        ++idxCurrByte;
        if (idxCurrByte >= 7) idxCurrByte = 0; // индекс по входящим байтам 0...6
    }
    return outCharPos+changeOutOffset;
}

// http://hardisoft.ru/soft/samodelkin-soft/poluchenie-i-dekodirovanie-sms-soobshhenij-v-formate-pdu/
void modemSMSprocessingLineText(void) {
    static unsigned char smsDataIndex; // индекс смс
    static unsigned char smsDataLenField; // длина данных из заголовка
    char * p1 = strstr((const char *) modemRXbuf, (const char *) "+CMGL: ");
    if ((p1) && (p1 >= ((const char *) modemRXbuf))) {
        // вытаскиваем индекс СМСки
        if (isdigit(*(p1+7))) {
            smsDataIndex = (*(p1+7)) - '0';
            if (isdigit(*(p1+8))) {
                smsDataIndex = smsDataIndex * 10 +(*(p1+8)) - '0';
            }
            printf("smsDataIndex %d\r\n", smsDataIndex);
            // вытаскиваем длину поля данных
            p1 = strchr((const char *) (p1 + 7), ',');
            if (p1) {
                char * p2 = strchr((const char *) (p1 + 1), ',');
                if (p2) {
                    p1 = strchr((const char *) (p2 + 1), ',');
                    if ((p1) && (p1>p2) && (isdigit(*(p1+1))) && (isdigit(*(p1+2)))) {
                        smsDataLenField = ((*(p1+1)) - '0') * 10 + ((*(p1+2)) - '0');
                        if (isdigit(*(p1+3))) {
                            smsDataLenField *= 10;
                            smsDataLenField += (*(p1+3)) - '0';
                        }
                        printf("smsDataLenField %d\r\n", smsDataLenField);
                        return; // строка успешно разпозналась - выходим
                    }
                }
            }
        }
    } else if ((smsDataIndex) && (smsDataLenField)) { // след строка уже будет опираться на предыдущие обработанные данные
        char * smsPcurrentCharPos = (char*) modemRXbuf; // начало строки с данными
        char * smsPendPosLine = strchr(smsPcurrentCharPos, '\r'); // последний символ строки с данными + 1
        unsigned short smsDataCharsLenLine = smsPendPosLine - smsPcurrentCharPos; // общая длина строки с данными
        if ((smsDataCharsLenLine % 2) == 0) { // количество символов должно быть четным
            if ((smsDataCharsLenLine / 2) >= smsDataLenField) { // есть ли заголовок TP-SCA (номер СМС центра)
                smsPcurrentCharPos += ((smsDataCharsLenLine/2) - smsDataLenField) * 2; // сдвигаем указатель строки начала данных вправо на длину TP-SCA
                t_TP_MTIandCo TP_MTIandCo;
                TP_MTIandCo.TP_MTI_Value = smsGetByteFromTwoChars(smsPcurrentCharPos); 
                printf("TP-MTI %d\r\n", TP_MTIandCo.TP_MTI);
                printf("TP-MMS %d\r\n", TP_MTIandCo.TP_MMS);
                printf("TP-SRI %d\r\n", TP_MTIandCo.TP_SRI);
                printf("TP-UDHI %d\r\n", TP_MTIandCo.TP_UDHI);
                printf("TP-RP %d\r\n", TP_MTIandCo.TP_RP);
                smsPcurrentCharPos += 2; // указатель сдвигаем на два символа вправо = 1 байт
                // адрес отправителя TP-OA
                unsigned char lenTP_OA = smsGetByteFromTwoChars(smsPcurrentCharPos); // длина строки отправителя
                smsPcurrentCharPos += 2; // указатель сдвигаем на два символа вправо = 1 байт
                unsigned char typeTP_OA = smsGetByteFromTwoChars(smsPcurrentCharPos); // формат строки отправителя
                smsPcurrentCharPos += 2; // указатель сдвигаем на два символа вправо = 1 байт
                unsigned char smsSender[16]; // отправитель
                switch (typeTP_OA) {
                    case 0x91: { // международный формат номера
                        unsigned char senderPos = 0;
                        while (senderPos < lenTP_OA) {
                            unsigned char ch1 = * (smsPcurrentCharPos + 1); // первый символ / перевернутая позиция
                            if (senderPos < lenTP_OA) {
                                smsSender[senderPos] = ch1; ++senderPos;
                            }
                            ch1 = * smsPcurrentCharPos; // второй символ // перевернутая позиция
                            if (senderPos < lenTP_OA) {
                                smsSender[senderPos] = ch1; ++senderPos;
                            }
                            smsPcurrentCharPos +=2;  // указатель сдвигаем на два символа вправо = 1 байт
                        }
                        smsSender[senderPos] = '\0'; // конец строки
                        break;
                    }
                    default: { // тут остальные форматы номера,которые еще не запрограммированы, например текстовый отправитель, тупо сдвигаем позицию на нужгное кол.байт
                        unsigned char senderPos = 0;
                        while (senderPos < lenTP_OA) {
                            if (senderPos < lenTP_OA) {
                                smsSender[senderPos] = * smsPcurrentCharPos; ++senderPos;
                            }
                            if (senderPos < lenTP_OA) {
                                smsSender[senderPos] = * (smsPcurrentCharPos + 1); ++senderPos;
                            }
                            smsPcurrentCharPos +=2;  // указатель сдвигаем на два символа вправо = 1 байт
                        }
                        smsSender[senderPos] = '\0'; // конец строки
                    }
                }
                printf("Sender %s\r\n", smsSender);
                // TP-PID  (Protocol identifier) – Идентификатор протокола. // не используем - пропускаем
                smsPcurrentCharPos +=2;  // указатель сдвигаем на два символа вправо = 1 байт
                // TP-DCS (Data coding scheme) – Схема кодирования данных.
                //  00 — 7-битная сжатая кодировка, 08 — UCS2, 10 и 18 — то же, только сообщение класса 0, т.е. Flash.
                unsigned char TP_DCS = smsGetByteFromTwoChars(smsPcurrentCharPos);
                printf("TP-DCS %02x\r\n", TP_DCS);
                smsPcurrentCharPos +=2;  // указатель сдвигаем на два символа вправо = 1 байт
                // TP-SCTS (The service centre time stamp) – Штамп времени сервисного центра. Не используем.
                smsPcurrentCharPos +=14;  // указатель сдвигаем на 7 байт
                // TP-UDL (User Data Length) — длина пользовательских данных, включая User Data header, если он есть. Если SMS закодирована 7-битной кодировкой, то данное поле указывает количество символов в сообщении. Если кодировка UCS2 – то поле указывает количество байт в сообщении.
                unsigned char TP_UDL = smsGetByteFromTwoChars(smsPcurrentCharPos);
                printf("TP-UDL %d\r\n", TP_UDL);
                smsPcurrentCharPos +=2;  // указатель сдвигаем на два символа вправо = 1 байт
                // TP-UD (User Data) – Поле пользовательских данных. Здесь находится сам текст сообщения. В случае, если SMS длинная, т.е. разбита на несколько сообщений, данное поле начинается с заголовка TP-UDH. На наличие этого заголовка указывает бит TP-UDHI поля TP-MTI & Co. 
                unsigned char smsMessage[161]; // текст одного сообщения, по стандарту максимум 160 байт + терминатор
                smsMessage[0] = '\0';
                if (TP_MTIandCo.TP_UDHI == 0) { // сообщение из одного блока
                    if ((TP_DCS == 0x00) || (TP_DCS == 0x10)) { // 7и битная кодировка
                        smsMessage[smsTextMsg7bit(smsPcurrentCharPos, smsPendPosLine, (char *) smsMessage, TP_UDL)] = '\0';
                    } else if ((TP_DCS == 0x08) || (TP_DCS == 0x18)) { // кодировка UCS2
                    }
                } else { // многоблочное сообщение
                    unsigned char UDHL = smsGetByteFromTwoChars(smsPcurrentCharPos);
                    printf("UDHL %02x\r\n", UDHL);
                    smsPcurrentCharPos +=2;  // указатель сдвигаем на два символа вправо = 1 байт
                    // UDH
                    // IEI Для отправки длинных сообщений всегда равен либо 0х00, либо 0х08. Если 0х00 – то IED1 занимает 1 байт, если 0х08 – то IED1 занимает 2 байта.
                    unsigned char IEI = smsGetByteFromTwoChars(smsPcurrentCharPos);
                    printf("IEI %02x\r\n", IEI);
                    smsPcurrentCharPos +=2;  // указатель сдвигаем на два символа вправо = 1 байт
                    // IEDL Длина данных информационного элемента – 3 или 4 байта, в зависимости от длины поля IED1
                    unsigned char IEDL = smsGetByteFromTwoChars(smsPcurrentCharPos);
                    printf("IEDL %02x\r\n", IEDL);
                    smsPcurrentCharPos +=2;  // указатель сдвигаем на два символа вправо = 1 байт
                    // IED1 Номер-ссылка. Должен быть одинаков для всех частей сообщения
                    unsigned short IED1;
                    if (IEI == 0x00) {
                        IED1 = smsGetByteFromTwoChars(smsPcurrentCharPos);
                        smsPcurrentCharPos +=2;  // указатель сдвигаем на два символа вправо = 1 байт
                    } else {
                        IED1 = smsGetByteFromTwoChars(smsPcurrentCharPos) * 256;
                        smsPcurrentCharPos +=2;  // указатель сдвигаем на два символа вправо = 1 байт
                        IED1 += smsGetByteFromTwoChars(smsPcurrentCharPos);
                        smsPcurrentCharPos +=2;  // указатель сдвигаем на два символа вправо = 1 байт
                    }
                    printf("IED1 %02x\r\n", IED1);
                    // IED2 Количество частей в сообщении
                    unsigned char IED2 = smsGetByteFromTwoChars(smsPcurrentCharPos);
                    printf("IED2 %02x\r\n", IED2);
                    smsPcurrentCharPos +=2;  // указатель сдвигаем на два символа вправо = 1 байт
                    // IED3 Порядковый номер части сообщения
                    unsigned char IED3 = smsGetByteFromTwoChars(smsPcurrentCharPos);
                    printf("IED3 %02x\r\n", IED3);
                    smsPcurrentCharPos +=2;  // указатель сдвигаем на два символа вправо = 1 байт
                    if ((TP_DCS == 0x00) || (TP_DCS == 0x10)) { // 7и битная кодировка
                        // считаем смещение септета
                        static unsigned short offset7bitFirstChar = 0;
                        unsigned short lenBytesWithUDH = TP_UDL*7/8; // длина поля UD с заголовком UDH
                        unsigned short lenBitsWOUDH = (lenBytesWithUDH - UDHL - 1) * 8; // длина поля с сообщением в битах уже без заголовка
                        unsigned short count7bitChars = lenBitsWOUDH / 7; // количество целиковых 7и битных символов
                        if ((IED3 == 1) && (IED2 > 1)) { // считаем для первой части сообщения, для остальных частей он аналогичный
                            offset7bitFirstChar = lenBitsWOUDH - (count7bitChars * 7); // filler	0-6 бит	Наполнитель, который выравнивает text по границе септета
                        }
                        smsMessage[smsTextMsg7bitWithOffset(smsPcurrentCharPos, smsPendPosLine, (char *) smsMessage, count7bitChars, offset7bitFirstChar)] = '\0';
                    } else if ((TP_DCS == 0x08) || (TP_DCS == 0x18)) { // кодировка UCS2
                    }
                }
                printf("%s\r\n", smsMessage);
            }
        }
    }
    smsDataIndex = 0; // если не распозналась и не обработалась СМСка // или успешно обработалось - обнуляем все что сделали
}

void modemCMDworkSMS(bool inLine) {
    static bool firstReadAllSMS = true;
    static unsigned long smsReqListTimer = 0;
    static unsigned long smsTimerWork;
    static tSMSmode smsCurrentMode = smsStNone;
    switch (smsCurrentMode) {
        case smsStGetList: {
            if (firstReadAllSMS) {
                uart_puts(UART_ID, (const char*)"AT+CMGL=4,0\r");
                printf("%s\n", "AT+CMGL=4,0\r\n");
                firstReadAllSMS = false;
            } else {
                return;
                uart_puts(UART_ID, (const char*)"AT+CMGL=0,0\r");
                printf("%s\n", "AT+CMGL=0,0\r\n");
            }
            smsTimerWork = millis();
            smsCurrentMode = smsStProcessing;
            break;
        }
        case smsStProcessing: {
            if ((millis() - smsTimerWork) >= 20000UL) {
                smsReqListTimer = millis();
                smsCurrentMode = smsStNone;
            } else if (inLine) {
                if (findOKRNfromBuf()) {
                    smsReqListTimer = millis();
                    smsCurrentMode = smsStNone;
                } else {
                    modemSMSprocessingLineText();
                }
            }
            break;
        }
        default: { // smsStNone
            if ((millis() - smsReqListTimer) >= period_read_sms) smsCurrentMode = smsStGetList;
        }
    }
}

void modemMainLoop(void) {
    switch (currentGlobalStatusModem) {
        case modemStBegin: {
            modemClearRXbuf();
            modemStepWork = 0;
            modemTimerWork = millis();
            currentGlobalStatusModem = modemStInit;
            break;
        }
        case modemStReboot: {
            modemReset();
            currentGlobalStatusModem = modemStBegin;
            break;
        }
        default: { // main work by modem
            unsigned char br = 0; // переменная куда падает входящий байт из модема
            bool flLine = false; // влаг что пришла целиковая строка
            while (uart_is_readable(UART_ID)) { // если что то пришло из модема
                br = uart_getc(UART_ID); // читаем пришедший байт
                if (br) { // если он больше нуля
                    modemRXbuf[modemPosBuf] = br; // кладем байт в буфер
                    ++modemPosBuf; // сдвигаем указатель на следующую позицию
                    if (modemPosBuf >= max_size_modem_rx_buf) {
                        modemPosBuf = 0; // начнем с начала буфера при переполнении
                        flLine = true; // флаг что конец строки
                        break; // выходим из цикла
                    }
                    if ((br == '\r') || (br == '\n') || ((br >= ' ') && (br < 0x7F))) { // если символ печатный или конец строки
                        printf("%c", br); // выводим как есть
                    } else { // если не печатный
                        printf("x%02x", br); // выводим его шестнадцатиричное представление в лог
                    }
                    if (((br == '\n') && (modemPosBuf > 1) && (modemRXbuf[modemPosBuf-2] == '\r')) ||
                        ((br == '\r') && (modemPosBuf > 1) && (modemRXbuf[modemPosBuf-2] == '\n'))) { // пришел конец строки
                        flLine = true; // флаг что конец строки
                        modemRXbuf[modemPosBuf] = '\0'; // прописываем терминатор/окончание строки
                        break; // выходим из цикла
                    }
                }
            }
            // начинаем запуск всех обработчиков данных
            switch (currentGlobalStatusModem) {
                case modemStInit: {
                    if (!modemCMDstInit(flLine)) currentGlobalStatusModem = modemStReboot;
                    break;
                }
                case modemStReg: {
                    if (!modemCMDstReg(flLine)) currentGlobalStatusModem = modemStReboot;
                    break;
                }
                case modemStReady: {
                    modemCMDworkSMS(flLine);
                    break;
                }
                default: {}
            }
            // остальные обработчики
            // если обработали целиковую строку
            if (flLine) modemClearRXbuf(); // обнуляем массив
            // end main work
        }
    }
    tight_loop_contents();
}

-

Start W5500
IP:  10.127.0.10
GW:  10.127.0.1
Net: 255.255.255.240
DNS1: 4.4.4.4
DNS2: 8.8.8.8
ATZ

OK
ATE0
ATE0
OK
ATV1

OK
AT+CMEE=2

OK
AT+CLIP=0

OK
ATS0=0

OK
AT+CSCLK=0

OK
AT+CREG?

+CREG: 0,1

OK
AT+COPS?

+COPS: 0,0,"MegaFon"

OK
AT+CSQ

+CSQ: 14,0

OK
AT+CMGF=0

OK
AT+CMGL=4,0


+CMGL: 1,1,"",39
smsDataIndex 1
smsDataLenField 39
07919702926033F1240B919702369149F600002290615193512116C6B47C4E07D1CB733A68DA9C8298617ADA1D0201
TP-MTI 0
TP-MMS 1
TP-SRI 1
TP-UDHI 0
TP-RP 0
Sender 79201111116
TP-DCS 00
TP-UDL 22
First test SMS Latin!

+CMGL: 2,1,"",25
smsDataIndex 2
smsDataLenField 25
07919702926033F1240B919702369149F600002290615104822106D4F29C0E9201
TP-MTI 0
TP-MMS 1
TP-SRI 1
TP-UDHI 0
TP-RP 0
Sender 79201111116
TP-DCS 00
TP-UDL 6
Test 2

+CMGL: 3,1,"",28
smsDataIndex 3
smsDataLenField 28
07919702926033F1240B919702369149F60000229061513451210AD3E6143403C1C3723A
TP-MTI 0
TP-MMS 1
TP-SRI 1
TP-UDHI 0
TP-RP 0
Sender 79201111116
TP-DCS 00
TP-UDL 10
SMS 3 part

+CMGL: 4,1,"",21
smsDataIndex 4
smsDataLenField 21
07919702926033F1240B919702369149F600002290616180542102521A
TP-MTI 0
TP-MMS 1
TP-SRI 1
TP-UDHI 0
TP-RP 0
Sender 79201111116
TP-DCS 00
TP-UDL 2
R4

+CMGL: 5,1,"",21
smsDataIndex 5
smsDataLenField 21
07919702926033F1240B919702369149F600002290616171222102B53C
TP-MTI 0
TP-MMS 1
TP-SRI 1
TP-UDHI 0
TP-RP 0
Sender 79201111116
TP-DCS 00
TP-UDL 2
5y

+CMGL: 6,1,"",159
smsDataIndex 6
smsDataLenField 159
07919702926033F1640B919702369149F6000022909161808021A0050003390201986FF71954749FD9E9391A346D4E41EE72990CA287E165503BED4EB7EB6D50CC06038DD161F91C7446A3CF665B8D263F83D075FA195DB7D9E86734089D3FD7F3799BCD763E83D0E873DE56AB99CFC6F3198D06D5CF67BAF98CCEA3D1209B8D7E3EA3D168F4F97C46A35DA0E3F99CB7D96A35FA198D06A1EBF433BA5E4783D2681CEE76B3E5CF
TP-MTI 0
TP-MMS 1
TP-SRI 1
TP-UDHI 1
TP-RP 0
Sender 79201111116
TP-DCS 00
TP-UDL 160
UDHL 05
IEI 00
IEDL 03
IED1 39
IED2 02
IED3 01
Long English SMS need tape minimum 160 chars ghhgf654rg hutghu66tgh hyguyy666gg hhgy655fgFgghh uggtfghyhh 66tgghhhhggghh. Gggy6655tghh hutghuuh ih88776yg

+CMGL: 7,1,"",54
smsDataIndex 7
smsDataLenField 54
07919702926033F1640B919702369149F600002290916180802127050003390202D06710FA8C46A3D168341A7D46A3D168B15A0D8286E57410FDFE0E8100
TP-MTI 0
TP-MMS 1
TP-SRI 1
TP-UDHI 1
TP-RP 0
Sender 79201111116
TP-DCS 00
TP-UDL 39
UDHL 05
IEI 00
IEDL 03
IED1 39
IED2 02
IED3 02
hg hghhhhhhhhghhhhbjj Part two!

OK

Update:

обновленный код - расшифровка в том числе русских СМС

#ifndef SIM800_PICO_H
#define SIM800_PICO_H

/// modem SIM800L UART
#define UART_ID uart0
#define BAUD_RATE 9600
#define DATA_BITS 8
#define STOP_BITS 1
#define PARITY    UART_PARITY_NONE
// We are using pins 12 and 13, but see the GPIO function select table in the
// datasheet for information on which other pins can be used.
#define UART_TX_PIN 12
#define UART_RX_PIN 13
#define pinResetModem 23 // пин сброса модема

//#define SHOW_DATASMS_LOG // вывести в лог всех данных об СМС

#define max_size_modem_rx_buf 2048 // приемный буфер данных от модема
#define period_wait_start_modem 15000UL // время ожидания модема после включения
#define period_wait_registration 120000UL // время ожидания регистрации модема в сети оператора
#define period_read_sms 10000UL // как часто с модема читать СМС

#define max_count_read_sms 20 // максимальное количество СМСок в массиве // частей СМС

enum tModemGlobalStatus {modemStBegin = 0, modemStInit, modemStReg, modemStReboot, modemStReady};

void modemInit(void); // инициализируем пины
void modemReset(void); // сброс модема
void modemMainLoop(void);

enum t_SMSprocessingStatus {smsPrEmpty = 0, smsPrHeader, smsPrReady};

union t_TP_MTIandCo {
    struct {
        unsigned TP_MTI:2;
        unsigned TP_MMS:1;
        unsigned res1:1;
        unsigned res2:1;
        unsigned TP_SRI:1;
        unsigned TP_UDHI:1;
        unsigned TP_RP:1;
    };
    unsigned char TP_MTI_Value;
};
 
struct t_OneSMS {
    t_SMSprocessingStatus smsStatus;
    unsigned char smsDataIndex; // индекс смс
    unsigned char smsDataLenField; // длина данных из заголовка
    t_TP_MTIandCo TP_MTIandCo;
    unsigned char smsSender[16]; // отправитель
    unsigned char TP_DCS; // TP-DCS (Data coding scheme) – Схема кодирования данных.
    //  00 — 7-битная сжатая кодировка, 08 — UCS2, 10 и 18 — то же, только сообщение класса 0, т.е. Flash.
    unsigned char TP_UDL; // TP-UDL (User Data Length) — длина пользовательских данных, включая User Data header, если он есть. Если SMS закодирована 7-битной кодировкой, то данное поле указывает количество символов в сообщении. Если кодировка UCS2 – то поле указывает количество байт в сообщении.
    // TP-UD (User Data) – Поле пользовательских данных. Здесь находится сам текст сообщения. В случае, если SMS длинная, т.е. разбита на несколько сообщений, данное поле начинается с заголовка TP-UDH. На наличие этого заголовка указывает бит TP-UDHI поля TP-MTI & Co. 
    unsigned char smsMessage[161]; // текст одного сообщения, по стандарту максимум 160 байт + терминатор
    unsigned char UDHL; // длина заголовка в многоблочном сообщении
    // UDH
    unsigned char IEI; // IEI Для отправки длинных сообщений всегда равен либо 0х00, либо 0х08. Если 0х00 – то IED1 занимает 1 байт, если 0х08 – то IED1 занимает 2 байта.
    unsigned char IEDL; // IEDL Длина данных информационного элемента – 3 или 4 байта, в зависимости от длины поля IED1
    unsigned short IED1; // IED1 Номер-ссылка. Должен быть одинаков для всех частей сообщения
    unsigned char IED2; // IED2 Количество частей в сообщении
    unsigned char IED3; // IED3 Порядковый номер части сообщения
};

#endif  /* SIM800_PICO_H */

#include <stdio.h>
#include "pico/stdlib.h"
#include "sim800pico.h"
#include "millpico.h"
#include <string.h>
#include <ctype.h>

tModemGlobalStatus currentGlobalStatusModem = modemStBegin;

unsigned char modemRXbuf[max_size_modem_rx_buf];
unsigned short modemPosBuf;
unsigned char modemStepWork;
unsigned long modemTimerWork = 0UL;
unsigned char operatorName[16];
unsigned char operatorCSQ;

t_OneSMS bufReadSMS[max_count_read_sms];

signed short findPosSubstringFromBuf(unsigned char * inStr) {
    char * pStr = strstr((const char *) modemRXbuf, (const char *) inStr);
    if (pStr) return (inStr - ((unsigned char*)pStr));
    else return -1;
}

bool findOKRNfromBuf(void) {
    if (findPosSubstringFromBuf((unsigned char *)"OK\r\n") >= 0) return true;
    else return false;
}

void initModemUART(void) {  // sim800 uart init
    // Set up our UART with the required speed.
    uart_init(UART_ID, BAUD_RATE);
    // Set the TX and RX pins by using the function select on the GPIO
    // Set datasheet for more information on function select
    gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);
    gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);
    // Use some the various UART functions to send out data
    // In a default system, printf will also output via the default UART
    // Send out a character without any conversions
    //uart_putc_raw(UART_ID, 'A');
    // Send out a character but do CR/LF conversions
    //uart_putc(UART_ID, 'B');
    // Send out a string, with CR/LF conversions
    //uart_puts(UART_ID, " Hello, UART!\n");
    // Actually, we want a different speed
    // The call will return the actual baud rate selected, which will be as close as
    // possible to that requested
    int __unused actual = uart_set_baudrate(UART_ID, BAUD_RATE);
    // Set UART flow control CTS/RTS, we don't want these, so turn them off
    uart_set_hw_flow(UART_ID, true, true);
    // Set our data format
    uart_set_format(UART_ID, DATA_BITS, STOP_BITS, PARITY);
    // Turn off FIFO's - we want to do this character by character
    uart_set_fifo_enabled(UART_ID, true);
}

void modemInit(void) {  // инициализируем пины и все остальное
    gpio_init(pinResetModem); // sim800 reset
    gpio_set_dir(pinResetModem, GPIO_IN); // sim800 reset
    gpio_put(pinResetModem, 0); // sim800 reset
    initModemUART(); // sim800 uart init
}

void modemReset(void) { // сброс модема
    gpio_set_dir(pinResetModem, GPIO_OUT);
    sleep_ms(115);
    gpio_set_dir(pinResetModem, GPIO_IN);
}

void modemClearRXbuf(void) {
    modemPosBuf = 0;
    memset(modemRXbuf, '\0', max_size_modem_rx_buf);
    //modemRXbuf[modemPosBuf] = '\0';
}

void modemSendCMDandShowAndTimerStep(unsigned char * inStr) {
    uart_puts(UART_ID, (const char*)inStr);
    printf("%s\n", inStr);
    modemTimerWork = millis(); // сбросим таймер
    ++modemStepWork; // На след шаг
}

bool processCREG(void) { // парсинг ответа модема на команду AT+CREG
    char * p1 = strstr((const char *) modemRXbuf, (const char *) "+CREG: ");
    if (p1) {
        if (p1 >= ((const char *) modemRXbuf)) {
            char * p2 = strchr((const char *) modemRXbuf, ',');
            if (p2) {
                if (p2 > p1) {
                    unsigned char br = *(p2+1);
                    if ((br == '1') || (br == '5')) return true;
                }
            }
        }
    }
    return false;
}

void processCOPS(void) { // парсинг ответа модема на команду AT+COPS
    char * p1 = strstr((const char *) modemRXbuf, (const char *) "+COPS: ");
    if (p1) {
        if (p1 >= ((const char *) modemRXbuf)) {
            char * p2 = strchr((const char *) modemRXbuf, ',');
            if (p2) {
                char * p3 = strchr((p2+1), ',');
                if (p3) {
                    if ((p3>p2) && ((*(p3+1)) == '"')) {
                        char * p4 = strchr((p3+2), '"');
                        if ((p4) && (p4>(p3+2))) {
                            unsigned char lenP = p4-p3-2;
                            for (unsigned char i=0; i<lenP; ++i) operatorName[i] = *(p3+2+i);
                            operatorName[lenP] = '\0';
                        }
                    }
                }
            }
        }
    }
}

void processCSQ(void) { // парсинг ответа модема на команду AT+CSQ
    char * p1 = strstr((const char *) modemRXbuf, (const char *) "+CSQ: ");
    if (p1) {
        if (p1 >= ((const char *) modemRXbuf)) {
            if (isdigit(*(p1+6))) {
                unsigned char tC = (*(p1+6)) - '0';
                if (isdigit(*(p1+7))) {
                    operatorCSQ = tC*10+((*(p1+7)) - '0');
                } else {
                    operatorCSQ = tC;
                }
            }
        }
    }
}

bool modemCMDstReg(bool inLine) {
    static unsigned long timerRegistration;
    static bool goodCREG;
    switch (modemStepWork) {
        case 0: {
            timerRegistration = millis();
            goodCREG = false;
            ++modemStepWork;
            break;
        }
        case 1: {
            modemSendCMDandShowAndTimerStep((unsigned char *)"AT+CREG?\r"); // проверяем зарегестрировался ли модем в сети
            break;
        }
        case 2: {
            if ((millis() - timerRegistration) >= period_wait_registration) return false;
            if ((millis() - modemTimerWork) >= 5000UL) { // больше 5 сек нет ответа
                modemTimerWork = millis(); // сбросим таймер
                modemStepWork = 25; // перейдем на паузу 5 секунд, что бы потом опять запросить статус регистрации
            } else {
                if (inLine) { // если пришла строка
                    if (processCREG()) goodCREG = true; // парсим строку - если зарегестрировались - ставим флаг
                    if (findOKRNfromBuf()) { // ищем ответ ОК
                        if (goodCREG) { // если успешно зарегестрировались
                            modemSendCMDandShowAndTimerStep((unsigned char *)"AT+COPS?\r"); // получить режим подключения к оператору и имя оператора
                            operatorName[0] = 0; // очищаем имя оператора
                        } else { // если так и не смогли зарегестрироваться
                            modemTimerWork = millis(); // сбросим таймер
                            modemStepWork = 25; // перейдем на паузу 5 секунд, что бы потом опять запросить статус регистрации
                        }
                    }
                }
            }
            break;
        }
        case 3: {
            if ((millis() - modemTimerWork) >= 5000UL) return false;
            if (inLine) { // если пришла строка
                processCOPS();
                if (findOKRNfromBuf()) {
                    modemSendCMDandShowAndTimerStep((unsigned char *)"AT+CSQ\r"); // запрос качества связи
                    operatorCSQ = 0;
                }
            }
            break;
        }
        case 4: {
            if ((millis() - modemTimerWork) >= 5000UL) return false;
            if (inLine) { // если пришла строка
                processCSQ();
                if (findOKRNfromBuf()) modemSendCMDandShowAndTimerStep((unsigned char *)"AT+CMGF=0\r"); // SMS в PDU формате
            }
            break;
        }
        case 5: {
            if ((millis() - modemTimerWork) >= 5000UL) return false;
            if (inLine && findOKRNfromBuf()) { // успешно закончили начальную инициализацию модема
                currentGlobalStatusModem = modemStReady;
                modemStepWork = 0;
            }
            break;
        }
        case 25: {
            if ((millis() - modemTimerWork) >= 5000UL) modemStepWork = 1; // прождали и опять вернулись на запрос регистрации
            break;
        }
        default: {}
    }
    return true;
}

bool modemCMDstInit(bool inLine) {
    switch (modemStepWork) {
        case 0: { // ждем пока модем прочухается
            if ((millis() - modemTimerWork) >= period_wait_start_modem) ++modemStepWork; // На след шаг
            break;
        }
        case 1: {
            modemSendCMDandShowAndTimerStep((unsigned char *)"ATZ\r"); // проверка связи с модемом AT / сброс настроек на default - ATZ
            break;
        }
        case 2: {
            if ((millis() - modemTimerWork) >= 5000UL) return false;
            if (inLine && findOKRNfromBuf()) modemSendCMDandShowAndTimerStep((unsigned char *)"ATE0\r"); // отключение(ATE0) ЭХО, т е модем в обратку не дублирует
            break;
        }
        case 3: {
            if ((millis() - modemTimerWork) >= 5000UL) return false;
            if (inLine && findOKRNfromBuf()) modemSendCMDandShowAndTimerStep((unsigned char *)"ATV1\r"); // развернуты подробный ответ от модема
            break;
        }
        case 4: {
            if ((millis() - modemTimerWork) >= 5000UL) return false;
            if (inLine && findOKRNfromBuf()) modemSendCMDandShowAndTimerStep((unsigned char *)"AT+CMEE=2\r"); // вывод подробных описаний ошибок
            break;
        }
        case 5: {
            if ((millis() - modemTimerWork) >= 5000UL) return false;
            if (inLine && findOKRNfromBuf()) modemSendCMDandShowAndTimerStep((unsigned char *)"AT+CLIP=0\r"); // отключение АОН
            break;
        }
        case 6: {
            if ((millis() - modemTimerWork) >= 5000UL) return false;
            if (inLine && findOKRNfromBuf()) modemSendCMDandShowAndTimerStep((unsigned char *)"ATS0=0\r"); // модем не берет трубку при входящем звонке
            break;
        }
        case 7: {
            if ((millis() - modemTimerWork) >= 5000UL) return false;
            if (inLine && findOKRNfromBuf()) modemSendCMDandShowAndTimerStep((unsigned char *)"AT+CSCLK=0\r"); // отключение работы энергосберегающего режима через пин DTR
            break;
        }
        case 8: {
            if ((millis() - modemTimerWork) >= 5000UL) return false;
            if (inLine && findOKRNfromBuf()) { // закончилась начальная инициализация
                modemStepWork = 0;
                currentGlobalStatusModem = modemStReg; // переходим в режим регистрации оператора
            }
            break;
        }
        default: {}
    }
    return true;
}

enum tSMSmode {smsStNone = 0, smsStGetList, smsStProcessing};

unsigned char smsGetByteFromTwoChars(char * inChars) {
    unsigned char c1 = *inChars;
    unsigned char outByte;
    if (isdigit(c1)) outByte = c1 - '0'; else outByte = c1 - 55;
    outByte *= 16;
    c1 = *(inChars + 1);
    if (isdigit(c1)) outByte += c1 - '0'; else outByte += c1 - 55;
    return outByte;
}

unsigned char smsTextMsg7bit(char * begStr, char * endStr, char * outBuf, unsigned char msgLen) {
    unsigned char outCharPos = 0; // позиция в выходном массиве
    char * currCharPos = begStr; // указатель на символ откуда берем байт
    unsigned char prevDataByte = 0; // предыдущий входящий байт
    while ((currCharPos < endStr) && (outCharPos < msgLen)) {
        unsigned char inDataByte = smsGetByteFromTwoChars(currCharPos); // входной байт
        currCharPos += 2; // сразу сдвинем указатель на два символа вправо = 1 байт данных
        unsigned char idxCurrByte = outCharPos % 8; // индекс сдвига входящего байта 0...7
        if (idxCurrByte) {
            unsigned char lowBits = prevDataByte >> (8 - idxCurrByte);
            *(outBuf+outCharPos) = ((inDataByte << idxCurrByte) & 0x7F) | lowBits;
            ++outCharPos;
            if (idxCurrByte == 7) {
                *(outBuf+outCharPos) = inDataByte;
                ++outCharPos;
            }
        } else {
            *(outBuf+outCharPos) = inDataByte & 0x7F;
            ++outCharPos;
        }
        prevDataByte = inDataByte; // сохраним для след байта данных
    }
    return outCharPos;
}

unsigned char smsTextMsg7bitWithOffset(char * begStr, char * endStr, char * outBuf, unsigned char msgLen, unsigned short inOffset) {
    char * currCharPos = begStr; // указатель на символ откуда берем байт
    unsigned char changeOutOffset = 0; // байт сдвига выходного буфера
    if (inOffset) { // если первый байт сдвигается
        *(outBuf) = smsGetByteFromTwoChars(currCharPos) >> inOffset; // кладем в выходной буфер со сдвигом
        currCharPos += 2; // сразу сдвинем указатель на два символа вправо = 1 байт данных
        changeOutOffset = 1; // будем на 1 символ больше класть в выходной буфер
    }
    unsigned char outCharPos = 0; // позиция в выходном массиве
    unsigned char prevDataByte = 0; // предыдущий входящий байт
    unsigned char idxCurrByte = 0; // индекс сдвига входящего байта 0...6
    while ((currCharPos < endStr) && ((outCharPos+changeOutOffset) < msgLen)) {
        unsigned char inDataByte = smsGetByteFromTwoChars(currCharPos); // входной байт
        currCharPos += 2; // сразу сдвинем указатель на два символа вправо = 1 байт данных
        if (idxCurrByte) {
            unsigned char lowBits = prevDataByte >> (8 - idxCurrByte);
            *(outBuf+outCharPos+changeOutOffset) = ((inDataByte << idxCurrByte) & 0x7F) | lowBits;
            ++outCharPos;
            if (idxCurrByte == 6) {
                *(outBuf+outCharPos+changeOutOffset) = inDataByte >> 1;
                ++outCharPos;
            }
        } else {
            *(outBuf+outCharPos+changeOutOffset) = inDataByte & 0x7F;
            ++outCharPos;
        }
        prevDataByte = inDataByte; // сохраним для след байта данных
        ++idxCurrByte;
        if (idxCurrByte >= 7) idxCurrByte = 0; // индекс по входящим байтам 0...6
    }
    return outCharPos+changeOutOffset;
}

unsigned char smsTextMsgUCS2(char * begStr, char * endStr, char * outBuf, unsigned char msgLen) {
    unsigned char outCharPos = 0; // позиция в выходном массиве
    char * currCharPos = begStr; // указатель на символ откуда берем байт
    while ((currCharPos < endStr) && (outCharPos < msgLen)) {
        unsigned char in1DataByte = smsGetByteFromTwoChars(currCharPos); // входной байт
        currCharPos += 2; // сразу сдвинем указатель на два символа вправо = 1 байт данных
        unsigned char in2DataByte = smsGetByteFromTwoChars(currCharPos); // входной байт
        currCharPos += 2; // сразу сдвинем указатель на два символа вправо = 1 байт данных
        if (!in1DataByte) { // ASCII
            *(outBuf+outCharPos) = in2DataByte;
            ++outCharPos;
        } else if (in1DataByte == 0x04) { // Unicode RUS
            if (in2DataByte == 0x01) {
                *(outBuf+outCharPos) = 0xD0;
                *(outBuf+outCharPos+1) = 0x81;
            } else if (in2DataByte == 0x51) {
                *(outBuf+outCharPos) = 0xD1;
                *(outBuf+outCharPos+1) = 0x91;
            } else if ((in2DataByte >= 0x10) && (in2DataByte <= 0x3F)) {
                *(outBuf+outCharPos) = 0xD0;
                *(outBuf+outCharPos+1) = 0x90 + (in2DataByte - 0x10);
            } else if ((in2DataByte >= 0x40) && (in2DataByte <= 0x4F)) {
                *(outBuf+outCharPos) = 0xD1;
                *(outBuf+outCharPos+1) = 0x80 + (in2DataByte - 0x40);
            } else { // other
                *(outBuf+outCharPos) = in1DataByte;
                *(outBuf+outCharPos+1) = in2DataByte;
            }
            outCharPos += 2;
        } else { // other
            *(outBuf+outCharPos) = in1DataByte;
            *(outBuf+outCharPos+1) = in2DataByte;
            outCharPos += 2;
        }
    }
    return outCharPos;
}

// http://hardisoft.ru/soft/samodelkin-soft/poluchenie-i-dekodirovanie-sms-...
void modemSMSprocessingLineText(void) {
    static unsigned char smsDataIndex; // индекс смс
    static unsigned char smsDataLenField; // длина данных из заголовка
    static unsigned char smsCurrentIndex; // текущий слот в буфере для обработки
    char * p1 = strstr((const char *) modemRXbuf, (const char *) "+CMGL: ");
    if ((p1) && (p1 >= ((const char *) modemRXbuf))) {
        // вытаскиваем индекс СМСки
        if (isdigit(*(p1+7))) {
            smsDataIndex = (*(p1+7)) - '0';
            if (isdigit(*(p1+8))) {
                smsDataIndex = smsDataIndex * 10 +(*(p1+8)) - '0';
            }
            // вытаскиваем длину поля данных
            p1 = strchr((const char *) (p1 + 7), ',');
            if (p1) {
                char * p2 = strchr((const char *) (p1 + 1), ',');
                if (p2) {
                    p1 = strchr((const char *) (p2 + 1), ',');
                    if ((p1) && (p1>p2) && (isdigit(*(p1+1))) && (isdigit(*(p1+2)))) {
                        smsDataLenField = ((*(p1+1)) - '0') * 10 + ((*(p1+2)) - '0');
                        if (isdigit(*(p1+3))) {
                            smsDataLenField *= 10;
                            smsDataLenField += (*(p1+3)) - '0';
                        }
                        // поиск в массиве СМС пустого слота
                        bool foundIdx = false; // флаг что нашелся индекс
                        for (unsigned char i=0; i<max_count_read_sms; ++i) {
                            if (bufReadSMS[i].smsStatus == smsPrEmpty) {
                                foundIdx = true;
                                smsCurrentIndex = i;
                                break;
                            }
                        }
                        if (foundIdx) {
                            bufReadSMS[smsCurrentIndex].smsStatus = smsPrHeader;
                            bufReadSMS[smsCurrentIndex].smsDataIndex = smsDataIndex;
                            bufReadSMS[smsCurrentIndex].smsDataLenField = smsDataLenField;
                        } else {
                            smsDataIndex = 0; // обнулим данные, что бы далее обработка не пошла
                            smsDataLenField = 0;  // обнулим данные, что бы далее обработка не пошла
                        }
                        // ----
                        return; // строка успешно разпозналась - выходим
                    }
                }
            }
        }
    } else if ((smsDataIndex) && (smsDataLenField) && (bufReadSMS[smsCurrentIndex].smsStatus = smsPrHeader)) { // след строка уже будет опираться на предыдущие обработанные данные
        char * smsPcurrentCharPos = (char*) modemRXbuf; // начало строки с данными
        char * smsPendPosLine = strchr(smsPcurrentCharPos, '\r'); // последний символ строки с данными + 1
        unsigned short smsDataCharsLenLine = smsPendPosLine - smsPcurrentCharPos; // общая длина строки с данными
        if ((smsDataCharsLenLine % 2) == 0) { // количество символов должно быть четным
            if ((smsDataCharsLenLine / 2) >= smsDataLenField) { // есть ли заголовок TP-SCA (номер СМС центра)
                smsPcurrentCharPos += ((smsDataCharsLenLine/2) - smsDataLenField) * 2; // сдвигаем указатель строки начала данных вправо на длину TP-SCA
                bufReadSMS[smsCurrentIndex].TP_MTIandCo.TP_MTI_Value = smsGetByteFromTwoChars(smsPcurrentCharPos); 
                smsPcurrentCharPos += 2; // указатель сдвигаем на два символа вправо = 1 байт
                // адрес отправителя TP-OA
                unsigned char lenTP_OA = smsGetByteFromTwoChars(smsPcurrentCharPos); // длина строки отправителя
                smsPcurrentCharPos += 2; // указатель сдвигаем на два символа вправо = 1 байт
                unsigned char typeTP_OA = smsGetByteFromTwoChars(smsPcurrentCharPos); // формат строки отправителя
                smsPcurrentCharPos += 2; // указатель сдвигаем на два символа вправо = 1 байт
                switch (typeTP_OA) {
                    case 0x91: { // международный формат номера
                        unsigned char senderPos = 0;
                        while (senderPos < lenTP_OA) {
                            unsigned char ch1 = * (smsPcurrentCharPos + 1); // первый символ / перевернутая позиция
                            if (senderPos < lenTP_OA) {
                                bufReadSMS[smsCurrentIndex].smsSender[senderPos] = ch1; ++senderPos;
                            }
                            ch1 = * smsPcurrentCharPos; // второй символ // перевернутая позиция
                            if (senderPos < lenTP_OA) {
                                bufReadSMS[smsCurrentIndex].smsSender[senderPos] = ch1; ++senderPos;
                            }
                            smsPcurrentCharPos +=2;  // указатель сдвигаем на два символа вправо = 1 байт
                        }
                        bufReadSMS[smsCurrentIndex].smsSender[senderPos] = '\0'; // конец строки
                        break;
                    }
                    default: { // тут остальные форматы номера,которые еще не запрограммированы, например текстовый отправитель, тупо сдвигаем позицию на нужгное кол.байт
                        unsigned char senderPos = 0;
                        while (senderPos < lenTP_OA) {
                            if (senderPos < lenTP_OA) {
                                bufReadSMS[smsCurrentIndex].smsSender[senderPos] = * smsPcurrentCharPos; ++senderPos;
                            }
                            if (senderPos < lenTP_OA) {
                                bufReadSMS[smsCurrentIndex].smsSender[senderPos] = * (smsPcurrentCharPos + 1); ++senderPos;
                            }
                            smsPcurrentCharPos +=2;  // указатель сдвигаем на два символа вправо = 1 байт
                        }
                        bufReadSMS[smsCurrentIndex].smsSender[senderPos] = '\0'; // конец строки
                    }
                }
                // TP-PID  (Protocol identifier) – Идентификатор протокола. // не используем - пропускаем
                smsPcurrentCharPos +=2;  // указатель сдвигаем на два символа вправо = 1 байт
                // TP-DCS (Data coding scheme) – Схема кодирования данных.
                //  00 — 7-битная сжатая кодировка, 08 — UCS2, 10 и 18 — то же, только сообщение класса 0, т.е. Flash.
                bufReadSMS[smsCurrentIndex].TP_DCS = smsGetByteFromTwoChars(smsPcurrentCharPos);
                smsPcurrentCharPos +=2;  // указатель сдвигаем на два символа вправо = 1 байт
                // TP-SCTS (The service centre time stamp) – Штамп времени сервисного центра. Не используем.
                smsPcurrentCharPos +=14;  // указатель сдвигаем на 7 байт
                // TP-UDL (User Data Length) — длина пользовательских данных, включая User Data header, если он есть. Если SMS закодирована 7-битной кодировкой, то данное поле указывает количество символов в сообщении. Если кодировка UCS2 – то поле указывает количество байт в сообщении.
                bufReadSMS[smsCurrentIndex].TP_UDL = smsGetByteFromTwoChars(smsPcurrentCharPos);
                smsPcurrentCharPos +=2;  // указатель сдвигаем на два символа вправо = 1 байт
                // TP-UD (User Data) – Поле пользовательских данных. Здесь находится сам текст сообщения. В случае, если SMS длинная, т.е. разбита на несколько сообщений, данное поле начинается с заголовка TP-UDH. На наличие этого заголовка указывает бит TP-UDHI поля TP-MTI & Co. 
                bufReadSMS[smsCurrentIndex].smsMessage[0] = '\0';
                if (bufReadSMS[smsCurrentIndex].TP_MTIandCo.TP_UDHI == 0) { // сообщение из одного блока
                    if ((bufReadSMS[smsCurrentIndex].TP_DCS == 0x00) || (bufReadSMS[smsCurrentIndex].TP_DCS == 0x10)) { // 7и битная кодировка
                        bufReadSMS[smsCurrentIndex].smsMessage[smsTextMsg7bit(smsPcurrentCharPos, smsPendPosLine, (char *) bufReadSMS[smsCurrentIndex].smsMessage, bufReadSMS[smsCurrentIndex].TP_UDL)] = '\0';
                    } else if ((bufReadSMS[smsCurrentIndex].TP_DCS == 0x08) || (bufReadSMS[smsCurrentIndex].TP_DCS == 0x18)) { // кодировка UCS2
                        bufReadSMS[smsCurrentIndex].smsMessage[smsTextMsgUCS2(smsPcurrentCharPos, smsPendPosLine, (char *) bufReadSMS[smsCurrentIndex].smsMessage, bufReadSMS[smsCurrentIndex].TP_UDL)] = '\0';
                    }
                } else { // многоблочное сообщение
                    bufReadSMS[smsCurrentIndex].UDHL = smsGetByteFromTwoChars(smsPcurrentCharPos);
                    smsPcurrentCharPos +=2;  // указатель сдвигаем на два символа вправо = 1 байт
                    // UDH
                    // IEI Для отправки длинных сообщений всегда равен либо 0х00, либо 0х08. Если 0х00 – то IED1 занимает 1 байт, если 0х08 – то IED1 занимает 2 байта.
                    bufReadSMS[smsCurrentIndex].IEI = smsGetByteFromTwoChars(smsPcurrentCharPos);
                    smsPcurrentCharPos +=2;  // указатель сдвигаем на два символа вправо = 1 байт
                    // IEDL Длина данных информационного элемента – 3 или 4 байта, в зависимости от длины поля IED1
                    bufReadSMS[smsCurrentIndex].IEDL = smsGetByteFromTwoChars(smsPcurrentCharPos);
                    smsPcurrentCharPos +=2;  // указатель сдвигаем на два символа вправо = 1 байт
                    // IED1 Номер-ссылка. Должен быть одинаков для всех частей сообщения
                    if (bufReadSMS[smsCurrentIndex].IEI == 0x00) {
                        bufReadSMS[smsCurrentIndex].IED1 = smsGetByteFromTwoChars(smsPcurrentCharPos);
                        smsPcurrentCharPos +=2;  // указатель сдвигаем на два символа вправо = 1 байт
                    } else {
                        bufReadSMS[smsCurrentIndex].IED1 = smsGetByteFromTwoChars(smsPcurrentCharPos) * 256;
                        smsPcurrentCharPos +=2;  // указатель сдвигаем на два символа вправо = 1 байт
                        bufReadSMS[smsCurrentIndex].IED1 += smsGetByteFromTwoChars(smsPcurrentCharPos);
                        smsPcurrentCharPos +=2;  // указатель сдвигаем на два символа вправо = 1 байт
                    }
                    // IED2 Количество частей в сообщении
                    bufReadSMS[smsCurrentIndex].IED2 = smsGetByteFromTwoChars(smsPcurrentCharPos);
                    smsPcurrentCharPos +=2;  // указатель сдвигаем на два символа вправо = 1 байт
                    // IED3 Порядковый номер части сообщения
                    bufReadSMS[smsCurrentIndex].IED3 = smsGetByteFromTwoChars(smsPcurrentCharPos);
                    smsPcurrentCharPos +=2;  // указатель сдвигаем на два символа вправо = 1 байт
                    if ((bufReadSMS[smsCurrentIndex].TP_DCS == 0x00) || (bufReadSMS[smsCurrentIndex].TP_DCS == 0x10)) { // 7и битная кодировка
                        // считаем смещение септета
                        static unsigned short offset7bitFirstChar = 0;
                        unsigned short lenBytesWithUDH = bufReadSMS[smsCurrentIndex].TP_UDL*7/8; // длина поля UD с заголовком UDH
                        unsigned short lenBitsWOUDH = (lenBytesWithUDH - bufReadSMS[smsCurrentIndex].UDHL - 1) * 8; // длина поля с сообщением в битах уже без заголовка
                        unsigned short count7bitChars = lenBitsWOUDH / 7; // количество целиковых 7и битных символов
                        if ((bufReadSMS[smsCurrentIndex].IED3 == 1) && (bufReadSMS[smsCurrentIndex].IED2 > 1)) { // считаем для первой части сообщения, для остальных частей он аналогичный
                            offset7bitFirstChar = lenBitsWOUDH - (count7bitChars * 7); // filler	0-6 бит	Наполнитель, который выравнивает text по границе септета
                        }
                        bufReadSMS[smsCurrentIndex].smsMessage[smsTextMsg7bitWithOffset(smsPcurrentCharPos, smsPendPosLine, (char *) bufReadSMS[smsCurrentIndex].smsMessage, count7bitChars, offset7bitFirstChar)] = '\0';
                    } else if ((bufReadSMS[smsCurrentIndex].TP_DCS == 0x08) || (bufReadSMS[smsCurrentIndex].TP_DCS == 0x18)) { // кодировка UCS2
                        bufReadSMS[smsCurrentIndex].smsMessage[smsTextMsgUCS2(smsPcurrentCharPos, smsPendPosLine, (char *) bufReadSMS[smsCurrentIndex].smsMessage, bufReadSMS[smsCurrentIndex].TP_UDL)] = '\0';
                    }
                }
                #ifdef SHOW_DATASMS_LOG
                    printf("smsDataIndex %d\r\n", smsDataIndex);
                    printf("smsDataLenField %d\r\n", smsDataLenField);
                    printf("TP-MTI %d\r\n", bufReadSMS[smsCurrentIndex].TP_MTIandCo.TP_MTI);
                    printf("TP-MMS %d\r\n", bufReadSMS[smsCurrentIndex].TP_MTIandCo.TP_MMS);
                    printf("TP-SRI %d\r\n", bufReadSMS[smsCurrentIndex].TP_MTIandCo.TP_SRI);
                    printf("TP-UDHI %d\r\n", bufReadSMS[smsCurrentIndex].TP_MTIandCo.TP_UDHI);
                    printf("TP-RP %d\r\n", bufReadSMS[smsCurrentIndex].TP_MTIandCo.TP_RP);
                    printf("Sender %s\r\n", bufReadSMS[smsCurrentIndex].smsSender);
                    printf("TP-DCS %02x\r\n", bufReadSMS[smsCurrentIndex].TP_DCS);
                    printf("TP-UDL %d\r\n", bufReadSMS[smsCurrentIndex].TP_UDL);
                    if (!bufReadSMS[smsCurrentIndex].TP_MTIandCo.TP_UDHI) {
                        printf("UDHL %02x\r\n", bufReadSMS[smsCurrentIndex].UDHL);
                        printf("IEI %02x\r\n", bufReadSMS[smsCurrentIndex].IEI);
                        printf("IEDL %02x\r\n", bufReadSMS[smsCurrentIndex].IEDL);
                        printf("IED1 %04x\r\n", bufReadSMS[smsCurrentIndex].IED1);
                        printf("IED2 %02x\r\n", bufReadSMS[smsCurrentIndex].IED2);
                        printf("IED3 %02x\r\n", bufReadSMS[smsCurrentIndex].IED3);
                    }
                    printf("Text SMS %d index:\r\n", smsCurrentIndex);
                    printf("%s\r\n", bufReadSMS[smsCurrentIndex].smsMessage);
                #endif
                bufReadSMS[smsCurrentIndex].smsStatus = smsPrReady;
            }
        }
    }
    smsDataIndex = 0; // если не распозналась и не обработалась СМСка // или успешно обработалось - обнуляем все что сделали
}

void modemCMDworkSMS(bool inLine) {
    static bool firstReadAllSMS = true;
    static unsigned long smsReqListTimer = 0;
    static unsigned long smsTimerWork;
    static tSMSmode smsCurrentMode = smsStNone;
    switch (smsCurrentMode) {
        case smsStGetList: {
            if (firstReadAllSMS) {
                uart_puts(UART_ID, (const char*)"AT+CMGL=4,0\r");
                printf("%s\n", "AT+CMGL=4,0\r\n");
                firstReadAllSMS = false;
            } else {
                //return; // если только один раз читать все СМС при старте
                uart_puts(UART_ID, (const char*)"AT+CMGL=0,0\r");
                printf("%s\n", "AT+CMGL=0,0\r\n");
            }
            smsTimerWork = millis();
            smsCurrentMode = smsStProcessing;
            break;
        }
        case smsStProcessing: {
            if ((millis() - smsTimerWork) >= 20000UL) {
                smsReqListTimer = millis();
                smsCurrentMode = smsStNone;
            } else if (inLine) {
                if (findOKRNfromBuf()) {
                    smsReqListTimer = millis();
                    smsCurrentMode = smsStNone;
                } else {
                    modemSMSprocessingLineText();
                }
            }
            break;
        }
        default: { // smsStNone
            if ((millis() - smsReqListTimer) >= period_read_sms) smsCurrentMode = smsStGetList;
        }
    }
}

void modemMainLoop(void) {
    switch (currentGlobalStatusModem) {
        case modemStBegin: {
            modemClearRXbuf();
            modemStepWork = 0;
            modemTimerWork = millis();
            currentGlobalStatusModem = modemStInit;
            break;
        }
        case modemStReboot: {
            modemReset();
            currentGlobalStatusModem = modemStBegin;
            break;
        }
        default: { // main work by modem
            unsigned char br = 0; // переменная куда падает входящий байт из модема
            bool flLine = false; // влаг что пришла целиковая строка
            while (uart_is_readable(UART_ID)) { // если что то пришло из модема
                br = uart_getc(UART_ID); // читаем пришедший байт
                if (br) { // если он больше нуля
                    modemRXbuf[modemPosBuf] = br; // кладем байт в буфер
                    ++modemPosBuf; // сдвигаем указатель на следующую позицию
                    if (modemPosBuf >= max_size_modem_rx_buf) {
                        modemPosBuf = 0; // начнем с начала буфера при переполнении
                        flLine = true; // флаг что конец строки
                        break; // выходим из цикла
                    }
                    if ((br == '\r') || (br == '\n') || ((br >= ' ') && (br < 0x7F))) { // если символ печатный или конец строки
                        printf("%c", br); // выводим как есть
                    } else { // если не печатный
                        printf("x%02x", br); // выводим его шестнадцатиричное представление в лог
                    }
                    if (((br == '\n') && (modemPosBuf > 1) && (modemRXbuf[modemPosBuf-2] == '\r')) ||
                        ((br == '\r') && (modemPosBuf > 1) && (modemRXbuf[modemPosBuf-2] == '\n'))) { // пришел конец строки
                        flLine = true; // флаг что конец строки
                        modemRXbuf[modemPosBuf] = '\0'; // прописываем терминатор/окончание строки
                        break; // выходим из цикла
                    }
                }
            }
            // начинаем запуск всех обработчиков данных
            switch (currentGlobalStatusModem) {
                case modemStInit: {
                    if (!modemCMDstInit(flLine)) currentGlobalStatusModem = modemStReboot;
                    break;
                }
                case modemStReg: {
                    if (!modemCMDstReg(flLine)) currentGlobalStatusModem = modemStReboot;
                    break;
                }
                case modemStReady: {
                    modemCMDworkSMS(flLine);
                    break;
                }
                default: {}
            }
            // остальные обработчики
            // если обработали целиковую строку
            if (flLine) modemClearRXbuf(); // обнуляем массив
            // end main work
        }
    }
    tight_loop_contents();
}


 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

andycat пишет:
Самое приятное, с моей точки зрения:простота работы с периферией по сравнению с stm32 cmsis. Sdk хорОш!

а у нутрях ядра cmsis присутствует )))
PS а у MBED и CMSIS и HAL ...

rkit
Offline
Зарегистрирован: 23.11.2016

cmsis это стандарт arm, он есть везде и он отвратительный.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

rkit пишет:

cmsis это стандарт arm, он есть везде и он отвратительный.

...есть осталось только дерьмо мамонта... зато его много... (из анекдота)

mixail844
Offline
Зарегистрирован: 30.04.2012

rkit пишет:

cmsis это стандарт arm, он есть везде и он отвратительный.

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

 

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

ua6em пишет:

[MBED

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

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

rkit пишет:

cmsis это стандарт arm, он есть везде и он отвратительный.

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

 

Buldakov
Offline
Зарегистрирован: 17.01.2016

А кто нибудь пробовал RP2040 подключать к LCD 1602 экрану? Нахожу пока только поврежденные библиотеки. 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Buldakov пишет:

А кто нибудь пробовал RP2040 подключать к LCD 1602 экрану? Нахожу пока только поврежденные библиотеки. 

А что, есть проблемы?

Buldakov
Offline
Зарегистрирован: 17.01.2016

Да, есть проблема. Ни одна библиотека из zip формата не распаковывается, поскольку программа не может найти файл с расширением *.h

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Buldakov пишет:

Да, есть проблема. Ни одна библиотека из zip формата не распаковывается, поскольку программа не может найти файл с расширением *.h

вот эта и распаковывается и компилируется, подключать дисплей влом (обязан работать)

smoki
Offline
Зарегистрирован: 24.10.2015

Привет, подскажите что я делаю не так компилирую программу в main.uf2, перезагружаю с зажатым boot, закидываю на появившийся диск программу, она запускается и работает, но если перезагрузить плату программа больше не запускается. Только если опять закидывать через boot.

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

Нет, это неправильно, так быть не должно.
Где то в инете лежит что то типа clean.uf2, программа, которая чистить флэш и прочее в МК. Попробуйте его. Или другую прогу скомпилировать, понять так же себя МК ведёт или нет.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

andycat пишет:
Нет, это неправильно, так быть не должно. Где то в инете лежит что то типа clean.uf2, программа, которая чистить флэш и прочее в МК. Попробуйте его. Или другую прогу скомпилировать, понять так же себя МК ведёт или нет.

я в таком случае заливаю разные версии питона

smoki
Offline
Зарегистрирован: 24.10.2015

Я компилирую через wsl (ubuntu ) по win10, если через arduino ide 2.0 то все ок.

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

smoki пишет:
wsl

а зачем так сложно?

rp2040 sdk под linux прекрасно разворачивается и работает без всяких лишних прокладок.

Morroc
Offline
Зарегистрирован: 24.10.2016

ua6em пишет:

делители float бывают только в сказках... 

с натяжкой в синтезаторах вроде si5351, там правда оно из несколько коэффициентов и отдельный PLL

Aleksk
Offline
Зарегистрирован: 08.06.2016

В коде сообщения #292  ошибка, белый цвет так не получить.

Вместо логического сложения (дизъюнкции, операции «ИЛИ») хитрый кетаец вставил просто сложение "+".  Зачем???

 

Надо так -
 
print("white")
for j in range(0, 100):
    for i in range(NUM_LEDS): 
        ar[i] = j<<16 | j<<8 | j 
 
 
было -
  ar[i] = j<<16 + j<<8 + j 

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Aleksk пишет:

В коде сообщения #292  ошибка, белый цвет так не получить.

Вместо логического сложения (дизъюнкции, операции «ИЛИ») хитрый кетаец вставил просто сложение "+".  Зачем???

 

Надо так -
 
print("white")
for j in range(0, 100):
    for i in range(NUM_LEDS): 
        ar[i] = j<<16 | j<<8 | j 
 
 
было -
  ar[i] = j<<16 + j<<8 + j 

 

к сожалению в посте код уже не поправить, надо выкладывать новую правленную функцию

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

В данном случае разницы между + и | нет !

0 +1 = 1

и

0 | 1 = 1

Второй операнд в данном примере всегда 0.

Aleksk
Offline
Зарегистрирован: 08.06.2016

ua6em пишет:

к сожалению в посте код уже не поправить, надо выкладывать новую правленную функцию

Кому надо разберутся.  

24 битное слово определяет яркость и цвета в RGB светодиоде WS2812. 
GGGGGGGGRRRRRRRRBBBBBBBB 
Старшие 8 бит  - GGGGGGGG - зелёный с яркостью от 0 до 255
Средние 8 бит - RRRRRRRR - красный  с яркостью от 0 до 255
Младшие 8 бит - BBBBBBBB  - синий  с яркостью от 0 до 255
Aleksk
Offline
Зарегистрирован: 08.06.2016

Komandir пишет:

В данном случае разницы между + и | нет !

0 +1 = 1

и

0 | 1 = 1

Второй операнд в данном примере всегда 0.

Так не будет работать, т.к.  используются не один бит (с помощью побитовых операций сдвига и логического сложения формируется управляющее слово из 24 бит).

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

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

Aleksk пишет:

Вместо логического сложения (дизъюнкции, операции «ИЛИ») хитрый кетаец вставил просто сложение "+".  Зачем???

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

0110 0000 0000 +

0000 1100 0000 +

0000 0000 0011 = ? 

Потом расскажешь, чо получилось