• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Где взять описание отсутствующих в офф.доках функций?

JustACat

Moderator
Команда форума
Пришло время и мне задать нубский вопрос, и пусть те, кто уже прошел по граблям, похахают надо мной, но все же, желательно, помогут.

Итак, пытаюсь въехать в код. Если конкретно, то код из Sming. Хотя вроде это не имеет значения. SDK v 1.0.0
Ковыряю функцию:
Код:
Serial.systemDebugOutput();
Пытаюсь найти ее вызов, мне eclipse вроде бы показывает: class HardwareSerial который тут:
C:\Sming\Sming\SmingCore\HardwareSerial.h
(чтобы скопировать путь, пришлось открыть его в Notepad++ там так удобно, правой кнопкой по закладке и там все есть, в эклипсе такое не нашел)
Ок, значит реализация там же рядом в HardwareSerial.cpp Хорошо, нашли:
Код:
void HardwareSerial::systemDebugOutput(bool enabled)
{
    if (uart == UART_ID_0)
        os_install_putc1(enabled ? (void *)uart_tx_one_char : NULL);
    //else
    //    os_install_putc1(enabled ? (void *)uart1_tx_one_char : NULL); //TODO: Debug serial
}
Но дальше-то затык... Что такое os_install_putc1?
Эклипс мне уже не смог ответить на этот вопрос (может я не так чего нажимаю?)...
Хорошо, воспользуемся поиском по файлам в Notepad++.
Ага, нашли единственное место:
C:\Espressif\ESP8266_SDK\include\osapi.h
Код:
#define os_install_putc1 ets_install_putc1
Круто... Теперь ищем ets_install_putc1 и находим его вот тут:
C:\Sming\Sming\system\include\esp_systemapi.h
Код:
extern void ets_install_putc1(void *routine);
И еще вот тут:
C:\Espressif\ESP8266_SDK\ld\eagle.rom.addr.v6.ld
Код:
PROVIDE ( ets_install_putc1 = 0x4000242c );
Могу ошибаться, но из этого я делаю вывод, что это некая функция, которая скрывается где-то в закомпиленных уже либах и исходников к ней нет.

Чтож, но вопрос не в этом, вопрос в том: как понять дальше, что эта хреновина делает?

Попытки найти в pdf'ках от Espressif описание этих функций - ничего не дают.
Не, я понимаю, что дальше умные люди вооружаются дизассемблерами, либо еще чем-то и...
Но мой вопрос стоит именно так: простые смертные могут где-то найти информацию, хотя бы общую, что делает и/или как работает та или иная функция, которая не описана в доках от Espressif?
То есть может где-то собран этот кладезь знаний уже? Может я не туда куда-то смотрю?

Пните меня в нужном направлении, и я как ежик, с удовольствием туда полечу! Спасибо! :)

PS: и да, мне не нужно объяснять конкретно эту вот строчку:
os_install_putc1(enabled ? (void *)uart_tx_one_char : NULL);
Я логикой ее понимаю, что-то вроде: прописываем куда-то в системе указатель на колбек-функцию, которую система будет вызывать каждый раз, когда захочет вывести 1 символ дебажной информации, а в этой функции мы уже этот символ выводим туда, куда нам надо, например, в UART0. Либо прописываем NULL, и тогда система не вызывает никокой функции и дебаг не выводится.
Но мне, например, не понятно, почему эта функция называется os_install_putc1/ets_install_putc1, то есть не может ли быть так, что она не только дебажную информацию выводит, но и что-то еще?
Почему не os_install_debug_putc какой-нибудь?// В общем, беда-беда, огорчение :)

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

pvvx

Активный участник сообщества
Не, я понимаю, что дальше умные люди вооружаются дизассемблерами, либо еще чем-то и...
Но мой вопрос стоит именно так: простые смертные могут где-то найти информацию, хотя бы общую, что делает и/или как работает та или иная функция, которая не описана в доках от Espressif?
Найдете только в своем компе, если сами положили её туда :)
То есть может где-то собран этот кладезь знаний уже? Может я не туда куда-то смотрю?
Частично собран, но находится на тысячах носителей, которые не желают объединяться.

os_install_putc1(enabled ? (void *)uart_tx_one_char : NULL); - это если enabled != 0, то будет включена функция вывода для printf и т.д. uart_tx_one_char(). А если enabled == 0, то вывода у системных функций типа printf не будет. Всё это обращается к кодам в BIOS-ROM и её системе ввода-вывода и т.д.
Код:
ROM:40001CB0 off_40001CB0    .int dword_3FFFDD3C     ; DATA XREF: ROM:eprintf_init_bufr
ROM:40001CB0                                         ; ROM:40001CDFr ...
....
ROM:4000242C ets_install_putc1:                      ; CODE XREF: ROM:40002441j
ROM:4000242C                                         ; DATA XREF: default_exception_handler:a_ets_install_putc1o
ROM:4000242C                 l32r            a3, off_40001CB0
ROM:4000242F                 s32i.n          a2, a3, 0xC
ROM:40002431                 ret.n
ROM:40002431 ; ---------------------------------------------------------------------------
ROM:40002433                 .byte 0
ROM:40002434 a_putc1         .int uart1_write_char   ; DATA XREF: ROM:ets_install_uart_printfr
ROM:40002434                                         ; ROM:40002566r
ROM:40002438 ; ---------------------------------------------------------------------------
ROM:40002438
ROM:40002438 ets_install_uart_printf:                ; CODE XREF: ROM:40000FFEj
ROM:40002438                 l32r            a2, a_putc1
ROM:4000243B                 addi            a1, a1, 0xF0
ROM:4000243E                 s32i            a0, a1, 0
ROM:40002441                 call0           ets_install_putc1
ROM:40002444                 l32i.n          a0, a1, 0
ROM:40002446                 addi            a1, a1, 0x10
ROM:40002449                 ret.n
ROM:40002449 ; ---------------------------------------------------------------------------
 
Последнее редактирование:

JustACat

Moderator
Команда форума
Всё это обращается к кодам в BIOS-ROM и её системе ввода-вывода и т.д.
Вот я и говорю, что по логике-то я это понимаю. Но хотелось бы некое подтверждение иметь.

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

JustACat

Moderator
Команда форума
А нет, наврал, не сохраняется... По умолчанию дебаг включен, и если не вызвать Serial.systemDebugOutput(false); (которая в Sming и вызывает дальше отключение), то отладка появляется в терминале...
Значит тогда получается, что я так и не могу толком разобраться со всеми этими Target'ами в этом eclipse... Да еще и в купе с запутанной памятью в ESP.
Чего и как компилить и шить правильно, чтобы программа работала так, как написано?
Конечно можно каждый раз делать clean - all - flash , но это долго, особенно в Sming там билдится куча библиотек каждый раз...
А если только all - flash , не всегда оно корректно и происходит...

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

d946

New member
Что такое os_install_putc1
типичная реализация связки printf и putchar (в нашем случае os_install_putc1)

Код:
void * func_putchar = NULL;

void os_install_putc1( (void *)putchar_cb){
     func_putchar= putchar_cb;
}

void os_printf(void *str, ...){
  char buf[1024];
  os_sprintf((char *)buf, str, ...);
  if (func_putchar!=NULL){
    while(*buf){
       func_putchar(*buf);
       buf++;
    }
  }
Дополнительная информация http://we.easyelectronics.ru/Soft/formatnyy-vyvod-na-si-dlya-mikrokontrollerov.html
 

JustACat

Moderator
Команда форума
d946, спасибо за инфу, но как я уже и говорил, меня интересует не конкретно данная строчка, а вообще принцип добывания информации по функциям SDK.
То есть, если мне, к примеру, нужно понять, что за функция и как работает на php, я знаю, что надо идти на php.net, там просто ввести эту функцию в строку поиска и получить по ней зачастую исчерпывающие данные... Вот то же самое меня интересует и тут. А os_install_putc1 я привел лишь как частный пример такого поиска...
Но вам в любом случае спасибо!
 

pvvx

Активный участник сообщества
То есть, если мне, к примеру, нужно понять, что за функция и как работает
Этот вопрос может разрешить только Espressif, путем создания полного SDK, а не огрызка.
А пока на их форуме присутствует единственная правильная рекомендация - использовать реверс :), т.е. дизасм.
Часть, того, что я смотрел по своим нуждам и было время и возможность как-то перевести дизасм на язык СИ вложено в исходники к моей веб свалке в папке "Хлам" :) Это всего малая часть кусков из общего бардака по дизасму, которые не совсем страшные ...
 
Последнее редактирование:

Victor

Administrator
Команда форума
единственная правильная рекомендация - использовать реверс
Здравствуйте, pvvx!
Раз уж вы не спите, не подскажете можно ли реверснуть бут и пропатчить NOP там, где вывод мусора в UART0. Или переключить его на UART1, или еще какие варианты есть.
 

pvvx

Активный участник сообщества
Здравствуйте, pvvx!
Раз уж вы не спите, не подскажете можно ли реверснуть бут и пропатчить NOP там, где вывод мусора в UART0. Или переключить его на UART1, или еще какие варианты есть.
Не выйдет - основные сообщения при старте в оба UART дает ROM-BIOS и от этого не избавится. Надо новую ревизию чипа.
Или речь о сообщениях при старте boot_vX.X.bin от Espressif?
 
Последнее редактирование:

pvvx

Активный участник сообщества
Код:
void call_user_start(void)
{
    init_sflash_start();
    ets_run();
}
Так стартует SDK в app_main.c.
А далее в SDK 1.0.0 приписали ненужную и глючную разборку по заголовку в flash и всякие выводы времени компиляции и т.д.
В библиотеке libmain.a они спецом смешали всю ненужную белиберду в один модуль app_main.o, чтобы это простой перепаковкой либы и заменой малого obj было не решить.
 

pvvx

Активный участник сообщества
ну мы ведь и не ждали от них ничего лучшего. а жаль.
Там главное, что при старте у них везде опять стоит:
Код:
    while(READ_PERI_REG(UART_STATUS(0))  & (UART_TXFIFO_CNT<<UART_TXFIFO_CNT_S));
    while(READ_PERI_REG(UART_STATUS(1))  & (UART_TXFIFO_CNT<<UART_TXFIFO_CNT_S));
и тем самым увеличивает время до старта рабочих процедур и не позволяет уменьшить потребление чипа при просыпаниях в deep_sleep c отключенным WiFi для опроса датчиков...
Но их не интересует ничего кроме Iot SDK для работы со своим сайтом. AT прошивка - это второстепенное и случайное образование :)
 

pvvx

Активный участник сообщества
Ещё по поводу старта:
Если при настройке параметров WiFi (конкретнее при сохранении параметров в flash) выключить или пропадет питание модуля, то при следующем старте вполне получите дамп памяти:
Код:
struct ets_FlashHeader { // заголовок flash (использует загрузчик BIOS)
    uint8 id; // = 0xE9
    uint8 number_segs; // Number of segments
    uint8 spi_interface; // SPI Flash Interface (0 = QIO, 1 = QOUT, 2 = DIO, 0x3 = DOUT)
    struct esp_flash_hsz hsz; // options
}  __attribute__((packed));

struct ets_store_wifi_hdr { // 0x4027F000 (пишется в последний сектор)
    uint8 bank;     // +00 = 0, 1 // используется первый или второй сектор настроек WiFi
    uint32 flag;    // +04 = 0x55AA55AA
    uint32 x;         // +08 = 0x00000119
    uint32 xx[2];    // +12 = 28, 28
    uint32 chk[2];    // +20 = 0x91, 0x91
};
void hex_damp_sec_blk_flash(uint32 fsec, uint32 len)
{
    uint8* buf = pvPortMalloc(len+3);
    if(spi_flash_read(fsec << 12, (uint32_t *)buf, len & 0xfffc) == SPI_FLASH_RESULT_OK) {
        uint8* ptr = buf;
        uint32 i = 0;
        while(len--) {
            os_printf_plus("%08x ", *ptr++);
            if((++i & 0x1F) == 0) os_printf_plus("\n");
        }
    }
    os_printf_plus("\n");
    vPortFree(buf);
}
void system_param_error(uint32 fsec)
{
    os_printf_plus("system param error\n");
    hex_damp_sec_blk_flash(fsec + 1, 0x370 ); // первый сектор сохранения параметров WiFi и размер структуры
    hex_damp_sec_blk_flash(fsec + 2, 0x370 ); // второй сектор сохранения параметров WiFi и размер структуры
    hex_damp_sec_blk_flash(fsec + 3, 28 ); // третий сектор заголовка сохранения параметров WiFi и размер это структуры
}

static void init_sflash_start(void)
{
    struct ets_FlashHeader fhead;
    uint8 wifi_cfg[0x370];
    struct ets_store_wifi_hdr buf;
    uint8 macaddr[6];

    read_macaddr_from_otp(&macaddr);

    SET_PERI_REG_MASK(SPI_USER(0), SPI_CS_SETUP); // +1 такт перед CS
    SPIRead(0, (uint32_t *)fhead, sizeof(fhead));

    uint8_t speed = fhead.hsz.spi_freg;
    if (speed >= 3) {
        speed = (speed == 0x15) ? 1 : 2; 
    } else {
        speed += 2;
    }

    uint32 fsize = 0x80000;
    switch(fhead.hsz.flash_size)
    {
        case 1:
            fsize = 0x40000;
            break;
        case 2:
            fsize = 0x100000;
            break;
        case 3:
            fsize = 0x200000;
            break;
        case 4:
            fsize = 0x400000;
            break;
    }
    flashchip->chip_size = fsize;
    sflash_something(speed);

    uint32 fsector = flashchip->chip_size >> 12;
    fsector -= 4;

    SPIRead(flashchip->chip_size - 0x1000,(uint32_t *)buf, sizeof(buf));

    uint32 store_cfg_addr = flashchip->chip_size - 0x3000 + ((buf.bank)? 0x1000 : 0);

    SPIRead(store_cfg_addr, &wifi_cfg, sizeof(wifi_cfg));

    Cache_Read_Enable(0,0,1);
    mem_clr_bss();
    ets_install_putc1(uart1_write_char_ram);
    if(buf.flag != 0x55AA55AA){
        if(buf.flag != 0xFFFFFFFF) {
            system_param_error(fsector);
        }
    }
    if(buf.chk[(buf.bank)? 1 : 0] != system_get_checksum((uint8 *)&wifi_cfg, sizeof(wifi_cfg)){
        system_param_error(fsector);
    }
....
}
Аналогично и при нестандартных размерах flash :) Но об этом уже писал и давал что выводится в UART этот дамп с "system param error\n"...
 
Сверху Снизу