• Почему файл после многократного количество циклов записи перестает быть доступен для открытия (fopen)?

    @Vadimatorikda Автор вопроса
    Karpion, полагаю, во всем виноват -m32 для сборки под x32. Он необходим, потому что у меня там freertos-имитация. А он (freertos) рухнет, если собрать под x64. Там грязные хаки с указателями во имя скорости и запрет собираться под x64 от разработчиков.
  • Почему файл после многократного количество циклов записи перестает быть доступен для открытия (fopen)?

    @Vadimatorikda Автор вопроса
    Успех. Цель достигнута. В итоге работает адекватно с open/write/read/close. Рабочий код выглядит так.
    int sdio_read (uint32_t *buf, uint32_t block_num, uint32_t num_block) {
        int sd = open(FILE_MICROSD_PATH, O_RDONLY);
        if (sd == -1) {
            return -1;
        };
    
        int rv = lseek(sd, block_num*SD_BLOCK_SIZE, SEEK_SET);
        if (rv != block_num*SD_BLOCK_SIZE) {
            close(sd);
            return -1;
        }
    
        ssize_t read_byte_num = 0;
        while (read_byte_num != SD_BLOCK_SIZE*num_block) {
            ssize_t real_read_byte_num = read(sd, &buf[read_byte_num], SD_BLOCK_SIZE*num_block - read_byte_num);
            if (real_read_byte_num == -1) {
                close(sd);
                return -1;
            }
    
            read_byte_num += real_read_byte_num;
        }
    
        rv = close(sd);
        return rv;
    }
    
    int sdio_write (const uint32_t *buf, uint32_t block_num, uint32_t num_block) {
        int sd = open(FILE_MICROSD_PATH, O_WRONLY);
        if (sd == -1) {
            return -1;
        };
    
        int rv = lseek(sd, block_num*SD_BLOCK_SIZE, SEEK_SET);
        if (rv != block_num*SD_BLOCK_SIZE) {
            close(sd);
            return -1;
        }
    
        ssize_t write_byte_num = 0;
        while (write_byte_num != SD_BLOCK_SIZE*num_block) {
            ssize_t real_write_byte_num = write(sd, &buf[write_byte_num], SD_BLOCK_SIZE*num_block - write_byte_num);
            if (real_write_byte_num == -1) {
                close(sd);
                return -1;
            }
    
            write_byte_num += real_write_byte_num;
        }
    
        rv = close(sd);
        return rv;
    }
  • Почему файл после многократного количество циклов записи перестает быть доступен для открытия (fopen)?

    @Vadimatorikda Автор вопроса
    Так. Убрал все лишнее. Все потоки, ОС-имитацию. Оставил только выше приведенные функции. Поведение не изменилось. В errno так же пусто (0). Попробую вариант с open/write/read/close.
  • Почему файл после многократного количество циклов записи перестает быть доступен для открытия (fopen)?

    @Vadimatorikda Автор вопроса

    1) Мне не нравится static FILE *sd Я бы сделал локальные переменные внутри обеих функций. При многопоточном программировании со статическими переменными - можно поиметь проблему.
    До кучи можно указать, что они регистровые.

    С файловой системой гарантировано работает один поток. Но согласен. Просто изначально была мысль открывать файл в начале и закрывать в конце (работы приложения). Но это оказалось плохой идеей, поскольку приложение по сути является бесконечным и его остановка по Ctrl + C не даст должного эффекта (файл не будет закрыт и что там будет на момент закрытия - не ясно). Про пункт - сделаю локальной в каждой функции. Сейчас это уместно.
    2) При отладке можно ставить задержку хоть в десять секунд. Тут надо найти источник проблемы, эффективность работы программы на этапе поиска ошибки совершенно не важна.

    Хорошо. Попробую.
    3) "После возвращения NULL из fopen в errno -переменной пусто." - противоречит мануалу. Я понимаю, что реальность сильнее мануала - но такого быть не должно. Напишите актуальный на данный код вместо старого в головном посте.

    Это возможно из-за того, что в приложении еще крутится планировщик, который меняет контекст задач (да, сейчас в приложении много потоков, один из которых работает с файловой системой. Это пусти запущенная ос (freertos) как приложение под linux). Он мог так же перетирать errno. Сейчас оставлю только базовый поток (в котором main) и отключу вообще весь функционал ОС. Чтобы убедиться что планировщик не виноват (я расставлял перед обращениями к fopen/fclose переход в критическую секцию, чтобы гарантировать, что контекст не будет переключен, но все же лучше вообще сейчас избавиться от всего лишнего).
    4) Кстати, errno - статическая. Т.е. при многопоточном программировании - её может затереть другой поток.

    Сейчас оставлю один поток, как сказал выше, и проверю еще раз.
    5) По правилам хорошего тона - в зависимости от того, где произошла ошибка, надо возвращать разные значения. Не "-1", как Вы сделали, а разные.

    Тут не соглашусь. Эти функции являются прослойкой имитации работы с аппаратной периферией. И драйверу, который находится выше, все равно, какой код ошибки будет возвращен (FatFS). Для него все, что не 0, это ошибка и логика действий при этом одна и та же.
    6) Попробуйте отказаться от оптимизации при компиляции. См.пункт 2.

    Уже -O0 -g3. Писал об этом, когда перечислял флаги.
    7) Проверьте код завершения fclose().

    Он всегда возвращает 0. В errno так же пусто. Сейчас проверю без ОС, лишних потоков и прочего еще раз.
    8) Можно попробовать работать без буферизации. Ваш стиль работы с файлом - как бы намекает, что надо использовать open(), close(), read() и write() - без "f" в начале. Заодно избавитесь от от лишних расходов на буферизацию в user-space, которые здесь бесполезны.

    Соглашусь. На худой конец попробую и это.
  • Почему файл после многократного количество циклов записи перестает быть доступен для открытия (fopen)?

    @Vadimatorikda Автор вопроса
    Попробовал добавить предварительный сброс на диск перед закрытием файла после записи. Все равно не помогло. Причем сбрасывает на диск без ошибок.
    if (fflush(sd) != 0) {
            fclose(sd);
            sd = NULL;
            return -1;
        }
  • Почему файл после многократного количество циклов записи перестает быть доступен для открытия (fopen)?

    @Vadimatorikda Автор вопроса
    Попробовал поставить последний GCC-9 (ну и G++, multilib). Толку не дало. Хотя читать/писать стало на несколько секторов дальше.
  • Почему файл после многократного количество циклов записи перестает быть доступен для открытия (fopen)?

    @Vadimatorikda Автор вопроса
    Задержки до секунды точно не помогают. А вот про исследовать код... Я что-то и не подумал. В errno же должно писаться какой-то значение при возвращении NULL Сейчас проверю.
  • Как использовать const объект в разных файлах cpp без копирования (C++14)?

    @Vadimatorikda Автор вопроса
    Применил "Одиночка". А вариант с extern не проходил (ругался на многократное объявление). А у "Одиночка" есть один минус. Его присвоение происходит в реальном времени. Так что приходится передавать его параметром в команду-регистратор указателя на этот объект (например, есть класс работы с LCD экраном. В нем мы должны сделать функцию, которая принимает в реальном времени указатель на объект SPI и потом позволяет классу LCD использовать объект класса SPI (объявленный как "Одиночка") для инициализации LCD одним из методов реального времени).
  • Как использовать const объект в разных файлах cpp без копирования (C++14)?

    @Vadimatorikda Автор вопроса
    Армянское Радио: оформите ответом, зачту лучшим. Вот полезные ссылки на эту тему, если вдруг кто столкнется:
    раз и два.
    По сути, нужно запихать конструктор в private область и добавить внутрь класса метод (в publuc область) который возвращает указатель на const static объект.
  • Выбор типа переменной класса в зависимости от параметра шаблона (C++17, if constexpr)?

    @Vadimatorikda Автор вопроса
    Ваш вариант мне понравился, однако для данной задачи мне предложили более короткую запись:
    typedef typename std::conditional< FRAME == EC_SPI_CFG_DATA_FRAME::FRAME_8_BIT, uint8_t, uint16_t >::type spi_frame_size;
    mutable spi_frame_size* p_tx = nullptr;

    Хотя в более серьезных задачах, само собой, буду использовать ваш метод.
  • Как получить текст из QLineEdit ( PyQt5 )?

    Сергей Горностаев: зато у других будет меньше вопросов. Сам когда-то страдал, когда пришлось резко на питоне Qt интерфейс поднимать... Такой бы пример был бы очень кстати.
  • Выбор типа переменной класса в зависимости от параметра шаблона (C++17, if constexpr)?

    @Vadimatorikda Автор вопроса
    devalone: так вроде же добавлена возможность в C++17 использовать подобного рода конструкции в шаблонах.
  • Несовместимость gnu make 3.81 и 4.2.1. Как разрешить?

    @Vadimatorikda Автор вопроса
    jcmvbkbc: вручную значит... Хорошо, спасибо!)
  • Несовместимость gnu make 3.81 и 4.2.1. Как разрешить?

    @Vadimatorikda Автор вопроса
    Да, вы абсолютно правы. Я не заметил, что на машинах с 3.81 и 4.2.1 разные версии пакета FreeRTOS_for_stm32f2. Из-за этого и пошло. Если не секрет, то как вы поняли, что ошибка именно в отсутствии зависимости цели?
  • Для чего нужны в CPP системные методы _exit, _open, _read, _write, _lseek, _fstat, _link, _unlink, _stat, _close, _execve, _fork, _getpid, _isatty...?

    @Vadimatorikda Автор вопроса
    Слепой походу, не заметил очевидного. Последняя ссылка очень даже. Самое то. Спасибо.
  • Как вывести из constexpr функции сообщение об ошибке и прервать компиляцию (C++1y; C++14)?

    @Vadimatorikda Автор вопроса
    Про неявный static_cast интересно. У меня сами по себе структуры POD. Причем еще и с __attribute__((packed)) (т.к. некоторые классы будут потом просто копировать указанные пользователем данные без разбора). Вот какой вышел код, кстати говоря (ссылки в git-е и, на всякий случай, сюда: https://github.com/Vadimatorik/chiptune_player_2.2... и https://github.com/Vadimatorik/chiptune_player_2.2...
    Тоже самое сюда:
    spoiler
    #pragma once
    
    #include "stm32_f20x_f21x_port.h"
    
    /*
     * Структура инициализации всех выводов порта.
     */
    
    /*
     * ADC.
     */
    M_OBJ_PIN_CFG_ADC(adc_bat,      EC_PORT_NAME::A, EC_PORT_PIN_NAME::PIN_0);                      // ADC_BAT.
    M_OBJ_PIN_CFG_ADC(adc_right,    EC_PORT_NAME::A, EC_PORT_PIN_NAME::PIN_4);                      // ADC_RIGHT.
    M_OBJ_PIN_CFG_ADC(adc_left,     EC_PORT_NAME::B, EC_PORT_PIN_NAME::PIN_1);                      // ADC_LEFT.
    
    /*
     * EXTI кнопки.
     */
    const pin_config_check_param<EC_PORT_NAME::A, EC_PORT_PIN_NAME::PIN_1,  EC_PIN_MODE::INPUT,     EC_PIN_OUTPUT_CFG::NO_USE,      EC_PIN_SPEED::LOW,      EC_PIN_PULL::UP,        EC_PIN_AF::NO_USE,      EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        b_v_up;
    const pin_config_check_param<EC_PORT_NAME::A, EC_PORT_PIN_NAME::PIN_2,  EC_PIN_MODE::INPUT,     EC_PIN_OUTPUT_CFG::NO_USE,      EC_PIN_SPEED::LOW,      EC_PIN_PULL::UP,        EC_PIN_AF::NO_USE,      EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        b_v_down;
    
    /*
     * MIDI (USART2).
     */
    const pin_config_check_param<EC_PORT_NAME::A, EC_PORT_PIN_NAME::PIN_3,  EC_PIN_MODE::AF,        EC_PIN_OUTPUT_CFG::NO_USE,      EC_PIN_SPEED::MEDIUM,   EC_PIN_PULL::NO_USE,    EC_PIN_AF::USART2,      EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        midi_uart_rx;
    
    /*
     * LCD (SPI1 + TIMx).
     */
    const pin_config_check_param<EC_PORT_NAME::A, EC_PORT_PIN_NAME::PIN_5,  EC_PIN_MODE::AF,        EC_PIN_OUTPUT_CFG::NO_USE,      EC_PIN_SPEED::MEDIUM,   EC_PIN_PULL::NO_USE,    EC_PIN_AF::SPI1,        EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        lcd_clk;
    const pin_config_check_param<EC_PORT_NAME::A, EC_PORT_PIN_NAME::PIN_6,  EC_PIN_MODE::AF,        EC_PIN_OUTPUT_CFG::NO_USE,      EC_PIN_SPEED::MEDIUM,   EC_PIN_PULL::NO_USE,    EC_PIN_AF::SPI1,        EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        lcd_miso;
    const pin_config_check_param<EC_PORT_NAME::A, EC_PORT_PIN_NAME::PIN_7,  EC_PIN_MODE::AF,        EC_PIN_OUTPUT_CFG::NO_USE,      EC_PIN_SPEED::MEDIUM,   EC_PIN_PULL::NO_USE,    EC_PIN_AF::SPI1,        EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        lcd_mosi;
    const pin_config_check_param<EC_PORT_NAME::C, EC_PORT_PIN_NAME::PIN_4,  EC_PIN_MODE::OUTPUT,    EC_PIN_OUTPUT_CFG::PUSH_PULL,   EC_PIN_SPEED::MEDIUM,   EC_PIN_PULL::NO_USE,    EC_PIN_AF::NO_USE,      EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::SET>           lcd_res;
    const pin_config_check_param<EC_PORT_NAME::C, EC_PORT_PIN_NAME::PIN_5,  EC_PIN_MODE::OUTPUT,    EC_PIN_OUTPUT_CFG::PUSH_PULL,   EC_PIN_SPEED::MEDIUM,   EC_PIN_PULL::NO_USE,    EC_PIN_AF::NO_USE,      EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::RESET>         lcd_dc;
    const pin_config_check_param<EC_PORT_NAME::B, EC_PORT_PIN_NAME::PIN_2,  EC_PIN_MODE::OUTPUT,    EC_PIN_OUTPUT_CFG::PUSH_PULL,   EC_PIN_SPEED::MEDIUM,   EC_PIN_PULL::NO_USE,    EC_PIN_AF::NO_USE,      EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::RESET>         lcd__cs;
    
    /*
     * micro-sd (SDIO + GPIO).
     */
    const pin_config_check_param<EC_PORT_NAME::A, EC_PORT_PIN_NAME::PIN_8,  EC_PIN_MODE::INPUT,     EC_PIN_OUTPUT_CFG::NO_USE,      EC_PIN_SPEED::LOW,      EC_PIN_PULL::UP,        EC_PIN_AF::NO_USE,      EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        sd1_push;
    const pin_config_check_param<EC_PORT_NAME::D, EC_PORT_PIN_NAME::PIN_2,  EC_PIN_MODE::AF,        EC_PIN_OUTPUT_CFG::NO_USE,      EC_PIN_SPEED::FAST,     EC_PIN_PULL::NO_USE,    EC_PIN_AF::SDIO,        EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        sd1_smd;
    const pin_config_check_param<EC_PORT_NAME::C, EC_PORT_PIN_NAME::PIN_8,  EC_PIN_MODE::AF,        EC_PIN_OUTPUT_CFG::NO_USE,      EC_PIN_SPEED::FAST,     EC_PIN_PULL::NO_USE,    EC_PIN_AF::SDIO,        EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        sd1_d0;
    const pin_config_check_param<EC_PORT_NAME::C, EC_PORT_PIN_NAME::PIN_9,  EC_PIN_MODE::AF,        EC_PIN_OUTPUT_CFG::NO_USE,      EC_PIN_SPEED::FAST,     EC_PIN_PULL::NO_USE,    EC_PIN_AF::SDIO,        EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        sd1_d1;
    const pin_config_check_param<EC_PORT_NAME::C, EC_PORT_PIN_NAME::PIN_10, EC_PIN_MODE::AF,        EC_PIN_OUTPUT_CFG::NO_USE,      EC_PIN_SPEED::FAST,     EC_PIN_PULL::NO_USE,    EC_PIN_AF::SDIO,        EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        sd1_d2;
    const pin_config_check_param<EC_PORT_NAME::C, EC_PORT_PIN_NAME::PIN_11, EC_PIN_MODE::AF,        EC_PIN_OUTPUT_CFG::NO_USE,      EC_PIN_SPEED::FAST,     EC_PIN_PULL::NO_USE,    EC_PIN_AF::SDIO,        EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        sd1_d3;
    const pin_config_check_param<EC_PORT_NAME::C, EC_PORT_PIN_NAME::PIN_12, EC_PIN_MODE::AF,        EC_PIN_OUTPUT_CFG::NO_USE,      EC_PIN_SPEED::FAST,     EC_PIN_PULL::NO_USE,    EC_PIN_AF::SDIO,        EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        sd1_clk;
    
    /*
     * USB (USB_FS + GPIO).
     */
    const pin_config_check_param<EC_PORT_NAME::A, EC_PORT_PIN_NAME::PIN_9,  EC_PIN_MODE::INPUT,     EC_PIN_OUTPUT_CFG::NO_USE,      EC_PIN_SPEED::LOW,      EC_PIN_PULL::NO_USE,    EC_PIN_AF::NO_USE,      EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        otg_fs_vbus;
    const pin_config_check_param<EC_PORT_NAME::A, EC_PORT_PIN_NAME::PIN_11, EC_PIN_MODE::AF,        EC_PIN_OUTPUT_CFG::NO_USE,      EC_PIN_SPEED::HIGH,     EC_PIN_PULL::NO_USE,    EC_PIN_AF::OTG_FS,      EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        usb_dm;
    const pin_config_check_param<EC_PORT_NAME::A, EC_PORT_PIN_NAME::PIN_12, EC_PIN_MODE::AF,        EC_PIN_OUTPUT_CFG::NO_USE,      EC_PIN_SPEED::HIGH,     EC_PIN_PULL::NO_USE,    EC_PIN_AF::OTG_FS,      EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        usb_dp;
    
    /*
     * AY (GPIO + TIM1 + SPI3)
     */
    const pin_config_check_param<EC_PORT_NAME::A, EC_PORT_PIN_NAME::PIN_10, EC_PIN_MODE::OUTPUT,    EC_PIN_OUTPUT_CFG::PUSH_PULL,   EC_PIN_SPEED::MEDIUM,   EC_PIN_PULL::NO_USE,    EC_PIN_AF::NO_USE,      EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::RESET>         bdir;
    const pin_config_check_param<EC_PORT_NAME::A, EC_PORT_PIN_NAME::PIN_15, EC_PIN_MODE::OUTPUT,    EC_PIN_OUTPUT_CFG::PUSH_PULL,   EC_PIN_SPEED::LOW,      EC_PIN_PULL::NO_USE,    EC_PIN_AF::NO_USE,      EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::RESET>         ay_1_res;
    const pin_config_check_param<EC_PORT_NAME::B, EC_PORT_PIN_NAME::PIN_15, EC_PIN_MODE::OUTPUT,    EC_PIN_OUTPUT_CFG::PUSH_PULL,   EC_PIN_SPEED::LOW,      EC_PIN_PULL::NO_USE,    EC_PIN_AF::NO_USE,      EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::RESET>         ay_2_res;
    const pin_config_check_param<EC_PORT_NAME::C, EC_PORT_PIN_NAME::PIN_6,  EC_PIN_MODE::OUTPUT,    EC_PIN_OUTPUT_CFG::PUSH_PULL,   EC_PIN_SPEED::MEDIUM,   EC_PIN_PULL::NO_USE,    EC_PIN_AF::NO_USE,      EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::RESET>         bc1;
    const pin_config_check_param<EC_PORT_NAME::B, EC_PORT_PIN_NAME::PIN_0,  EC_PIN_MODE::AF,        EC_PIN_OUTPUT_CFG::PUSH_PULL,   EC_PIN_SPEED::FAST,     EC_PIN_PULL::NO_USE,    EC_PIN_AF::TIM1,        EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        ay_clk;
    const pin_config_check_param<EC_PORT_NAME::B, EC_PORT_PIN_NAME::PIN_3,  EC_PIN_MODE::AF,        EC_PIN_OUTPUT_CFG::NO_USE,      EC_PIN_SPEED::MEDIUM,   EC_PIN_PULL::NO_USE,    EC_PIN_AF::SPI3,        EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        spi_audio_clk;
    const pin_config_check_param<EC_PORT_NAME::B, EC_PORT_PIN_NAME::PIN_5,  EC_PIN_MODE::AF,        EC_PIN_OUTPUT_CFG::NO_USE,      EC_PIN_SPEED::MEDIUM,   EC_PIN_PULL::NO_USE,    EC_PIN_AF::SPI3,        EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        spi_audio_tx;
    const pin_config_check_param<EC_PORT_NAME::B, EC_PORT_PIN_NAME::PIN_6,  EC_PIN_MODE::INPUT,     EC_PIN_OUTPUT_CFG::NO_USE,      EC_PIN_SPEED::LOW,      EC_PIN_PULL::NO_USE,    EC_PIN_AF::NO_USE,      EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        shdn;
    const pin_config_check_param<EC_PORT_NAME::B, EC_PORT_PIN_NAME::PIN_8,  EC_PIN_MODE::OUTPUT,    EC_PIN_OUTPUT_CFG::PUSH_PULL,   EC_PIN_SPEED::MEDIUM,   EC_PIN_PULL::NO_USE,    EC_PIN_AF::NO_USE,      EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::RESET>         spi_audio_st_reg;
    const pin_config_check_param<EC_PORT_NAME::B, EC_PORT_PIN_NAME::PIN_14, EC_PIN_MODE::OUTPUT,    EC_PIN_OUTPUT_CFG::PUSH_PULL,   EC_PIN_SPEED::MEDIUM,   EC_PIN_PULL::NO_USE,    EC_PIN_AF::NO_USE,      EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::RESET>         cs_res;
    
    /*
     * SPI клавиатура (SPI общий AY, тут только вход).
     */
    const pin_config_check_param<EC_PORT_NAME::C, EC_PORT_PIN_NAME::PIN_7,  EC_PIN_MODE::INPUT,     EC_PIN_OUTPUT_CFG::NO_USE,      EC_PIN_SPEED::LOW,      EC_PIN_PULL::UP,        EC_PIN_AF::NO_USE,      EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        button_in;
    
    /*
     * SWD.
     */
    const pin_config_check_param<EC_PORT_NAME::A, EC_PORT_PIN_NAME::PIN_13, EC_PIN_MODE::AF,        EC_PIN_OUTPUT_CFG::PUSH_PULL,   EC_PIN_SPEED::LOW,      EC_PIN_PULL::UP,        EC_PIN_AF::SYS,         EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        swd_io;
    const pin_config_check_param<EC_PORT_NAME::A, EC_PORT_PIN_NAME::PIN_14, EC_PIN_MODE::AF,        EC_PIN_OUTPUT_CFG::PUSH_PULL,   EC_PIN_SPEED::LOW,      EC_PIN_PULL::DOWN,      EC_PIN_AF::SYS,         EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        swd_clk;
    
    /*
     * PWR.
     */
    const pin_config_check_param<EC_PORT_NAME::C, EC_PORT_PIN_NAME::PIN_0,  EC_PIN_MODE::OUTPUT,    EC_PIN_OUTPUT_CFG::PUSH_PULL,   EC_PIN_SPEED::LOW,      EC_PIN_PULL::NO_USE,    EC_PIN_AF::NO_USE,      EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::RESET>         on_5v;
    const pin_config_check_param<EC_PORT_NAME::C, EC_PORT_PIN_NAME::PIN_1,  EC_PIN_MODE::OUTPUT,    EC_PIN_OUTPUT_CFG::PUSH_PULL,   EC_PIN_SPEED::LOW,      EC_PIN_PULL::NO_USE,    EC_PIN_AF::NO_USE,      EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::SET>           power_on;
    const pin_config_check_param<EC_PORT_NAME::C, EC_PORT_PIN_NAME::PIN_14, EC_PIN_MODE::INPUT,     EC_PIN_OUTPUT_CFG::NO_USE,      EC_PIN_SPEED::LOW,      EC_PIN_PULL::NO_USE,    EC_PIN_AF::NO_USE,      EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        tp_st;
    const pin_config_check_param<EC_PORT_NAME::C, EC_PORT_PIN_NAME::PIN_15, EC_PIN_MODE::INPUT,     EC_PIN_OUTPUT_CFG::NO_USE,      EC_PIN_SPEED::LOW,      EC_PIN_PULL::NO_USE,    EC_PIN_AF::NO_USE,      EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        tp_ch;
    const pin_config_check_param<EC_PORT_NAME::B, EC_PORT_PIN_NAME::PIN_4,  EC_PIN_MODE::OUTPUT,    EC_PIN_OUTPUT_CFG::PUSH_PULL,   EC_PIN_SPEED::MEDIUM,   EC_PIN_PULL::NO_USE,    EC_PIN_AF::NO_USE,      EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::RESET>         ay1_on;
    const pin_config_check_param<EC_PORT_NAME::B, EC_PORT_PIN_NAME::PIN_12, EC_PIN_MODE::OUTPUT,    EC_PIN_OUTPUT_CFG::PUSH_PULL,   EC_PIN_SPEED::MEDIUM,   EC_PIN_PULL::NO_USE,    EC_PIN_AF::NO_USE,      EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::RESET>         ay2_on;
    
    /*
     * MICRO-SD SPI2 (SPI2 + GPIO).
     */
    const pin_config_check_param<EC_PORT_NAME::C, EC_PORT_PIN_NAME::PIN_2,  EC_PIN_MODE::AF,        EC_PIN_OUTPUT_CFG::NO_USE,      EC_PIN_SPEED::MEDIUM,   EC_PIN_PULL::NO_USE,    EC_PIN_AF::SPI2,        EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        sd2_rx;
    const pin_config_check_param<EC_PORT_NAME::C, EC_PORT_PIN_NAME::PIN_3,  EC_PIN_MODE::AF,        EC_PIN_OUTPUT_CFG::NO_USE,      EC_PIN_SPEED::MEDIUM,   EC_PIN_PULL::NO_USE,    EC_PIN_AF::SPI2,        EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        sd2_tx;
    const pin_config_check_param<EC_PORT_NAME::B, EC_PORT_PIN_NAME::PIN_13, EC_PIN_MODE::AF,        EC_PIN_OUTPUT_CFG::NO_USE,      EC_PIN_SPEED::MEDIUM,   EC_PIN_PULL::NO_USE,    EC_PIN_AF::SPI2,        EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        sd2__clk;
    const pin_config_check_param<EC_PORT_NAME::B, EC_PORT_PIN_NAME::PIN_7,  EC_PIN_MODE::OUTPUT,    EC_PIN_OUTPUT_CFG::PUSH_PULL,   EC_PIN_SPEED::MEDIUM,   EC_PIN_PULL::NO_USE,    EC_PIN_AF::NO_USE,      EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::RESET>         sd2_cs;
    const pin_config_check_param<EC_PORT_NAME::B, EC_PORT_PIN_NAME::PIN_9,  EC_PIN_MODE::INPUT,     EC_PIN_OUTPUT_CFG::NO_USE,      EC_PIN_SPEED::LOW,      EC_PIN_PULL::UP,        EC_PIN_AF::NO_USE,      EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        sd2_push;
    
    /*
     * BOOT-USART (USART3)
     */
    const pin_config_check_param<EC_PORT_NAME::B, EC_PORT_PIN_NAME::PIN_10, EC_PIN_MODE::AF,        EC_PIN_OUTPUT_CFG::NO_USE,      EC_PIN_SPEED::MEDIUM,EC_PIN_PULL::NO_USE,       EC_PIN_AF::USART3,      EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        boot_tx;
    const pin_config_check_param<EC_PORT_NAME::B, EC_PORT_PIN_NAME::PIN_11, EC_PIN_MODE::AF,        EC_PIN_OUTPUT_CFG::NO_USE,      EC_PIN_SPEED::MEDIUM,EC_PIN_PULL::NO_USE,       EC_PIN_AF::USART3,      EC_LOCKED::LOCKED,      EC_PIN_STATE_AFTER_INIT::NO_USE>        boot_rx;
    
    int ayplayer_port_init ( void );
    spoiler
    #include "ayplayer_port.h"
    
    const constexpr pin_config_t ayplayer_global_port_pin_cfg_1[] = {
        adc_bat, adc_right, adc_left,                                                                           // ADC.
        midi_uart_rx,                                                                                           // MIDI (USART2).
        lcd_clk, lcd_miso, lcd_mosi, lcd_res, lcd_dc, lcd__cs,                                                  // LCD (SPI1 + TIMx).
        sd1_push, sd1_smd, sd1_d0, sd1_d1, sd1_d2, sd1_d3, sd1_clk,                                             // micro-sd (SDIO + GPIO).
        otg_fs_vbus, usb_dm, usb_dp,                                                                            // USB (USB_FS + GPIO).
        bdir, ay_1_res, ay_2_res, bc1, ay_clk, spi_audio_clk, spi_audio_tx, shdn, spi_audio_st_reg, cs_res,     // AY (GPIO + TIM1 + SPI3)
        button_in,                                                                                              // SPI клавиатура (SPI общий AY, тут только вход).
        swd_io, swd_clk,                                                                                        // SWD.
        on_5v, power_on, tp_st, tp_ch, ay1_on, ay2_on,                                                          // PWR.
        sd2_rx, sd2_tx, sd2__clk, sd2_cs, sd2_push,                                                             // MICRO-SD SPI2 (SPI2 + GPIO).
        boot_tx, boot_rx                                                                                        // BOOT-USART (USART3).
    };
    
    const constexpr global_port ayplayer_global_port( ayplayer_global_port_pin_cfg_1, M_SIZE_ARRAY(ayplayer_global_port_pin_cfg_1) );
    
    int ayplayer_port_init ( void ) {
        return ( ayplayer_global_port.reinit_all_ports() == E_ANSWER_GP::SUCCESS )?0:-1;
    }
  • Как вывести из constexpr функции сообщение об ошибке и прервать компиляцию (C++1y; C++14)?

    @Vadimatorikda Автор вопроса
    Антон: не ясно просто, почему он считает экземпляр шаблона класса и упакованную структуру одной и той же сущностью. Меня конечно радует, что это так. Но таки не ясно.