Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Architecture: APP specific configuration files required #9825

Closed
gschorcht opened this issue Aug 22, 2018 · 18 comments
Closed

Architecture: APP specific configuration files required #9825

gschorcht opened this issue Aug 22, 2018 · 18 comments
Assignees
Labels
State: stale State: The issue / PR has no activity for >185 days Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation

Comments

@gschorcht
Copy link
Contributor

gschorcht commented Aug 22, 2018

Following the discussion in #8066, I would like to open another topic concerning the configuration of boards and MCUs. This topic came to mind when I tried to cope with the default configurations in device drivers for external devices like sensors.

Most drivers of such devices define their interface parameters, e.g. the pins used, in the driver_x_params.h header files according to the scheme

#ifndef DRIVER_X_PARAM_Y
#define DRIVER_X_PARAM_Y  (GPIO(0,0))
#endif

Since these header files include board.h, the only way to override this default configuration is to change board.h. This is the right way for boards with on-board devices.

However, for off-board devices, especially with general purpose boards like the Arduino Uno that might be used in different applications, it seems not be the right way to change board.h. Especially because board.h is part of the repository and changes in board definitions would affect all applications.

From my point of view, a third configuration file beside the MCU and the board configuration is needed that contains application specific configurations.

There could be an optional file application_conf.h that is always included automatically by the make infrastructure if it exists. It could reside outside the RIOT repository in application's source directory.

To be able to compile the same application for different boards with different configurations, the file name of the application specific configuration file might contain also the board name, e.g., 'application_arduino_due_conf.h'.

Comments are very welcome.

@jnohlgard
Copy link
Member

I think an application specific configuration file is a good idea. If you make use of the order of include directories in the gcc command line, you could even have transparent fallbacks for when a board specific configuration does not exist.
Something like:
INCLUDES += appdir/config/arduino-uno appdir/config/default riot/config/default

@aabadie
Copy link
Contributor

aabadie commented Aug 22, 2018

I think using a custom <driver>_params.h file in the application directory (with main.c) or board include directory would also work. It should be included first but I didn't test that recently. In order, application directory is included first, then board, then driver.

@jnohlgard
Copy link
Member

@aabadie good point. Additionally, using include_next in the right place could even let you augment the default params without overwriting them.

@gschorcht
Copy link
Contributor Author

gschorcht commented Aug 23, 2018

Using <driver>_params.h in conjunction with #include_next works perfectly. For example, having the file lis3dh_params.h

#define LIS3DH_PARAM_CS             (GPIO_PIN(0, 2))
#define LIS3DH_PARAM_INT1           (GPIO_PIN(0, 5))
#define LIS3DH_PARAM_INT2           (GPIO_PIN(0, 4))

#include_next "lis3dh_params.h"

in the application source directory, e.g., $(RIOTBASE)/tests/my_lis3dh_test and

INCLUDES += -I$(RIOTBASE)/tests/my_driver_lis3dh

in applications's makefile as first line before any other makefile is included, the default parameters defined in $(RIOTBASE)/drivers/lis3dh_params.h are overriden. Using #ifdef BOARD_<board> wrapper, you can even handle different boards.

This approach should be documented anywhere within an programmers guide.

Even tough this approach works, it doesn't make an application specific configuration unnecessary in following cases:

  1. override default definitions for different drivers
  2. override default definitions of the board configuration
  3. definition of application configurations

Item 2 becomes necessary for a general purpose board where you just have a number of GPIOs and the board doesn't define which GPIOs are used for what purposes. For such boards, RIOT's board maintainer would choose a default configuration according to his needs or his ideas. That is, he defines a default configuration of GPIOs that are defined as PWM channels, as ADC channels, as I2C signals a.s.o.

If this default configuration doesn't match the requirements of an application developer, at least some of the default configurations would have to be overridden. Unfortunately, the driver approach doesn't work for board.h, at least not with the current makefile infrastructure since -I$(RIOTBOARDS)/<board>/include is always in front of include pathes.

Item 3 may be required to control configurations other than driver parameters or board configurations, e.g. For example, what portion of the build-in flash memory is used for a built-in SPIFFs device.

In other projects something like make menuconfig is realized which provide a text-based menu driven configuration for application developers that then generate an application specific configuration file similar to riotbuild.h.

@jnohlgard
Copy link
Member

You could still do a lot with board.h and include_next, if you use #undef and redefine the board setting you want to override after the include_next

@kaspar030
Copy link
Contributor

We should consider the possibilities offered by cross file arrays (#9105).
As most configuration in RIOT is done through config structs in arrays, using XFA, these can be populated from anywhere.

Most driver.c include "driver_params.h", which in turn defines an array with one set of "default" settings. Initialization is up the caller (application has to call "driver_init(&driver_struct, driver_params").

Using XFA, the user could anywhere (e.g., app_config.c), do something like

driver_params_t my_driver = { .gpio=foo, ... }; XFA_ADD(driver_params, my_driver);

... and driver code could, through auto_init, automatically initialize all instances that have a corresponding struct entry in the driver's parameter cross file array.
The whole XFA line can be hidden in a macro like "DRIVER_FOO_CONFIG(GPIO_PIN(blah), ...```.

The same principle works for periph instances.

@kaspar030
Copy link
Contributor

BTW, there's a newly created "configuration task force" tackling exactly this issue, which is about to create a mailing list.

@aabadie
Copy link
Contributor

aabadie commented Aug 23, 2018

there's a newly created "configuration task force" tackling exactly this issue, which is about to create a mailing list.

Why not just reuse an existing one (devel would be a good candidate) and keep the discussions public ? Other developers may not want to be part of the task force but could still interested in following the discussions.

@gschorcht
Copy link
Contributor Author

@kaspar030

BTW, there's a newly created "configuration task force" tackling exactly this issue, which is
about to create a mailing list.

Yes, I did remember that there was an email related to configuration in near past, but I couldn't find it in the mail archive.

@gschorcht
Copy link
Contributor Author

gschorcht commented Aug 23, 2018

BTW, I have seen for a lot of boards that peripheral configurations are done in periph_conf.h as following:

static const uart_conf_t uart_config[] = {
    {
        .dev        = USART2,
        ...
    },
    {
        .dev        = USART1,
        ...
    }
};

#define UART_NUMOF          (sizeof(uart_config) / sizeof(uart_config[0]))

That is, an instance of this structure is created in each unit that includes board.h. Is that the problem what the XFA approach addresses?

@kaspar030
Copy link
Contributor

Is that problem what the XFA approach addresses?

Yes. With XFA, one (or multiple) .c file defines array entries (which must have a unique symbol name), and XFA sorts it into a linker section specific to that type. periph/uart code would use XFA to get a pointer to the combined uart_config array.

@Citrullin
Copy link
Contributor

Why not just reuse an existing one (devel would be a good candidate) and keep the discussions public ? Other developers may not want to be part of the task force but could still interested in following the discussions.

@aabadie I am with you. Since I also had the same issue with this I would like to follow this discussion. Even if I currently don't know how to solve.

My solution before was just: Cloning RIOT into my app folder, adding a new board, changing the config, adding a feature. In my case: A radio driver. Worked fine, but I also think that there is room for improvement. Since I want to test the new CC11x driver in the future, I would be happy to do it in the new way :)

But on the other side I am not against this way. Eventually I want to design a new board with my sensors on it. Therefore it could be kind of the correct way to define a new board. Even if it is kind of inconvenient while prototyping. So maybe it is just a documentation issue.

@jia200x
Copy link
Member

jia200x commented Aug 29, 2018

@Citrullin @aabadie @gschorcht I just opened a GH issue for tracking the status of the TF and some discussions at #9856

@miri64 miri64 added the Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation label Sep 1, 2018
@maribu
Copy link
Member

maribu commented Oct 8, 2018

A very simplistic approach could be this:

  • The build system checks if a header file with a special name, e.g. global_defines.h exists in the application folder.
  • If so, CFLAGS += -include "$(APPDIR)/global_defines.h". This would include that file as first header in every compilation unit
  • If <driver>_params.h, board.h and periph_conf.h surround their #defines by #ifndef <LABEL>...#endif, the default could be overwritten in global_defines.h. Most (maybe even all?) <driver>_params.h do that anyway :-)

@jia200x
Copy link
Member

jia200x commented Oct 8, 2018

@maribu there's #10077 that tries to tackle into this direction. If you could also provide feedback there would be nice :)

@stale
Copy link

stale bot commented Aug 10, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you want me to ignore this issue, please mark it with the "State: don't stale" label. Thank you for your contributions.

@stale stale bot added State: stale State: The issue / PR has no activity for >185 days and removed State: stale State: The issue / PR has no activity for >185 days labels Aug 10, 2019
@stale
Copy link

stale bot commented Feb 11, 2020

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you want me to ignore this issue, please mark it with the "State: don't stale" label. Thank you for your contributions.

@stale stale bot added the State: stale State: The issue / PR has no activity for >185 days label Feb 11, 2020
@gschorcht
Copy link
Contributor Author

The issue can be closed. Kconfig will be used to for application specific configuration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
State: stale State: The issue / PR has no activity for >185 days Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation
Projects
None yet
Development

No branches or pull requests

8 participants