Настройка фиктивного ввода-вывода в памяти во встроенных модульных тестах с использованием API на основе шаблонов - PullRequest
0 голосов
/ 03 апреля 2020

Я работаю над API на основе шаблонов для доступа к GPIO и другим периферийным устройствам на stm32f7xx. API основан на «Эффективном объектно-ориентированном и шаблонном программировании в реальном времени c ++» Кристофера Корманёса.

// gpio.h
template <std::uintptr_t BASE, std::uint8_t PIN>
class Gpio final {...}

// main.cpp
// this is how the API is usally used.
// note that GPIOA_BASE is defined in stm header files and 
// is an uint that directly points to the memory mapped IO
using gpio_a0 = Framework::Stm32F7xx::Gpio::Gpio<GPIOA_BASE, 0>;

Сама книга не тестируется, IMO пишет код без тестов. Поэтому я, наконец, решил догнать и запустить мой CMake с Gtest.

Моя проблема в том, что тесты скомпилированы для (хост / не ARM) -платформы, чтобы я мог запустить их в конвейере. Поэтому я не могу и не должен использовать определения из заголовочных файлов stm, такие как GPIOA_BASE. Так как они указывают на местоположение, которое НЕ доступно в тестах, выполняющих платформу. (Это приводит к SIGSEGV, поскольку я обращаюсь к памяти, я не должен)

Моя проблема сейчас. Как передать шаблон a uintptr_t, который указывает на область памяти размером: GPIO_Typedef и также определен во время компиляции?

Возможно ли это вообще? Есть ли другие варианты?

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

class GpioFixture : public ::testing::Test {
};

static constexpr char mem[sizeof(GPIO_TypeDef)] {};
static constexpr std::uintptr_t memptr = &mem; // <- this is not working

TEST_F(GpioFixture, ...){
    using gpio_a1 = Framework::Stm32F7xx::Gpio::Gpio<memptr, 1>;
    gpio_a1 a1 {...};

    // perform test

}

Редактировать: Поэтому основная проблема заключается в том, что мне нужно немного памяти, доступной в POINT X, и получить адрес это во время компиляции.

Так что я мог бы просто сделать using gpio_a0 = Framework::Stm32F7xx::Gpio::Gpio<0x..., 0>;

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

1 Ответ

1 голос
/ 06 апреля 2020
static constexpr char mem[sizeof(GPIO_TypeDef)] {};
static constexpr std::uintptr_t memptr = &mem; // <- this is not working

Проблема с этим фрагментом кода состоит в том, что вам потребуется constexpr reinterpret_cast для второй строки, что не разрешено языком. Я знаю, что это очень распространенный шаблон для встраиваемых устройств, и я лично надеялся, что std :: bit_cast или std :: bless , чтобы рассмотреть это, но похоже, что мы Обойтись без.

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

template <auto BASE, std::uint8_t PIN>
class Gpio {};

Функции-члены класса Gpio, в любом случае, должны будут интенсивно использовать reinterpret_cast, поэтому, например, set может выглядеть так:

static void set(uint32_t bit) {
  reinterpret_cast<GPIO_TypeDef*>(BASE)->BSRR = 1u << bit;
}

Поскольку параметр шаблона BASE теперь принимает указатели, вы даже можете передать указатель на экземпляр GPIO_TypeDef напрямую (в качестве приятного побочного эффекта это также решает проблему UB, поскольку параметр теперь фактически равен GPIO_TypeDef *):

GPIO_TypeDef mem{};
Gpio<&mem, 0u> gpio_a;

И на вашей цели вы можете продолжать использовать определения из заголовка STM32F7:

Gpio<GPIOA_BASE, 0u> gpio_a;

А также отвечать на вопрос из вашего последнего комментария

Но я совершенно не действительно понимаю, почему это не помогает при использовании constexpr.

Это может иметь две причины.

Создание экземпляра constexpr объекта GPIO_TypeDef также означает передачу указателя на объект const в класс шаблона. В случае, если у вас уже определены какие-либо функции-члены, которые reinterpret_cast в GPIO_TypeDef *, вы получите ошибку, что вы пытаетесь отбросить квалификатор const.

Также вы не можете создать экземпляры constexpr . не буквальные типы . GPIO_TypeDef не является литералом, так как все его члены непостоянны (скрыты за определением, называемым __IO).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...