gpiochips API, core and unit test (#703)
* Add external gpiochips driver API and core * gpiochips: add unit test
This commit is contained in:
parent
a3493e76ab
commit
70ebc06517
|
@ -132,6 +132,7 @@ include console/binary/tunerstudio.mk
|
||||||
include $(PROJECT_DIR)/ext/fatfs.mk
|
include $(PROJECT_DIR)/ext/fatfs.mk
|
||||||
|
|
||||||
include $(PROJECT_DIR)/hw_layer/hw_layer.mk
|
include $(PROJECT_DIR)/hw_layer/hw_layer.mk
|
||||||
|
include $(PROJECT_DIR)/hw_layer/drivers/drivers.mk
|
||||||
include $(PROJECT_DIR)/hw_layer/sensors/sensors.mk
|
include $(PROJECT_DIR)/hw_layer/sensors/sensors.mk
|
||||||
include $(PROJECT_DIR)/hw_layer/mass_storage/mass_storage.mk
|
include $(PROJECT_DIR)/hw_layer/mass_storage/mass_storage.mk
|
||||||
include $(PROJECT_DIR)/development/development.mk
|
include $(PROJECT_DIR)/development/development.mk
|
||||||
|
@ -181,6 +182,8 @@ CSRC = $(STARTUPSRC) \
|
||||||
$(CONSOLESRC) \
|
$(CONSOLESRC) \
|
||||||
$(DEV_SRC) \
|
$(DEV_SRC) \
|
||||||
$(HW_LAYER_EMS) \
|
$(HW_LAYER_EMS) \
|
||||||
|
$(HW_LAYER_DRIVERS_CORE) \
|
||||||
|
$(HW_LAYER_DRIVERS) \
|
||||||
$(CONTROLLERSSRC) \
|
$(CONTROLLERSSRC) \
|
||||||
$(CONTROLLERS_ALGO_SRC) \
|
$(CONTROLLERS_ALGO_SRC) \
|
||||||
$(CONTROLLERS_CORE_SRC) \
|
$(CONTROLLERS_CORE_SRC) \
|
||||||
|
@ -272,6 +275,7 @@ INCDIR = $(CHIBIOS)/os/license \
|
||||||
hw_layer/sensors \
|
hw_layer/sensors \
|
||||||
hw_layer/mass_storage \
|
hw_layer/mass_storage \
|
||||||
hw_layer/$(CPU_HWLAYER) \
|
hw_layer/$(CPU_HWLAYER) \
|
||||||
|
$(HW_LAYER_DRIVERS_INC) \
|
||||||
development \
|
development \
|
||||||
development/hw_layer \
|
development/hw_layer \
|
||||||
development/test \
|
development/test \
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
DRIVERS_DIR=$(PROJECT_DIR)/hw_layer/drivers
|
||||||
|
|
||||||
|
HW_LAYER_DRIVERS_INC = \
|
||||||
|
$(DRIVERS_DIR)
|
||||||
|
|
||||||
|
HW_LAYER_DRIVERS_CORE = \
|
||||||
|
$(DRIVERS_DIR)/gpio/core.c \
|
||||||
|
|
||||||
|
HW_LAYER_DRIVERS =
|
|
@ -0,0 +1,285 @@
|
||||||
|
/**
|
||||||
|
* @file gpio/core.c
|
||||||
|
* @brief EFI-related GPIO code for external gpio chips
|
||||||
|
*
|
||||||
|
* @date Mar 8, 2019
|
||||||
|
* @author Andrey Gusakov, (c) 2019
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
#include "gpio/gpio_ext.h"
|
||||||
|
|
||||||
|
#if (BOARD_EXT_GPIOCHIPS > 0)
|
||||||
|
|
||||||
|
/*==========================================================================*/
|
||||||
|
/* Local definitions. */
|
||||||
|
/*==========================================================================*/
|
||||||
|
|
||||||
|
/* fist available gpio number after on-chip gpios */
|
||||||
|
#define EXT_GPIOS_FIRST (GPIOH_15 + 1)
|
||||||
|
static size_t gpio_base_free = EXT_GPIOS_FIRST;
|
||||||
|
|
||||||
|
/*==========================================================================*/
|
||||||
|
/* Exported variables. */
|
||||||
|
/*==========================================================================*/
|
||||||
|
|
||||||
|
/*==========================================================================*/
|
||||||
|
/* Local variables and types. */
|
||||||
|
/*==========================================================================*/
|
||||||
|
|
||||||
|
/* TODO: chnage array to list? */
|
||||||
|
struct gpiochip {
|
||||||
|
size_t base;
|
||||||
|
size_t size;
|
||||||
|
struct gpiochip_ops *ops;
|
||||||
|
const char *name;
|
||||||
|
/* optional names of each gpio */
|
||||||
|
const char **gpio_names;
|
||||||
|
/* private driver data passed to ops */
|
||||||
|
void *priv;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct gpiochip chips[BOARD_EXT_GPIOCHIPS];
|
||||||
|
|
||||||
|
/*==========================================================================*/
|
||||||
|
/* Local functions. */
|
||||||
|
/*==========================================================================*/
|
||||||
|
|
||||||
|
static struct gpiochip *gpiochip_find(unsigned int pin)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < BOARD_EXT_GPIOCHIPS; i++) {
|
||||||
|
struct gpiochip *chip = &chips[i];
|
||||||
|
|
||||||
|
if ((pin >= chip->base) && (pin < (chip->base + chip->size)))
|
||||||
|
return chip;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*/
|
||||||
|
/* Exported functions. */
|
||||||
|
/*==========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return numeric part of EXTERNAL pin name.
|
||||||
|
* @details
|
||||||
|
*/
|
||||||
|
|
||||||
|
int getHwPinExt(unsigned int pin)
|
||||||
|
{
|
||||||
|
struct gpiochip *chip = gpiochip_find(pin);
|
||||||
|
|
||||||
|
if (chip)
|
||||||
|
return pin - chip->base;
|
||||||
|
|
||||||
|
return EFI_ERROR_CODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register gpiochip
|
||||||
|
* @details return pin name or gpiochip name (if no pins names provided)
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char *portNameExt(unsigned int pin)
|
||||||
|
{
|
||||||
|
struct gpiochip *chip = gpiochip_find(pin);
|
||||||
|
|
||||||
|
if (chip) {
|
||||||
|
if (chip->gpio_names)
|
||||||
|
return chip->gpio_names[pin - chip->base];
|
||||||
|
else
|
||||||
|
return chip->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register gpiochip
|
||||||
|
* @details should be called from board file. Can be called before os ready.
|
||||||
|
* All chips should be registered before gpiochips_init() called.
|
||||||
|
* returns -1 in case of no free chips left
|
||||||
|
* returns -1 in case of no ops provided, incorrect chip size
|
||||||
|
* else returns chip base
|
||||||
|
*/
|
||||||
|
|
||||||
|
int gpiochip_register(const char *name, struct gpiochip_ops *ops, size_t size, void *priv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct gpiochip *chip = NULL;
|
||||||
|
|
||||||
|
/* no ops provided, zero size? */
|
||||||
|
if ((!ops) || (!size))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((!ops->writePad) && (!ops->readPad))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* find free gpiochip struct */
|
||||||
|
for (i = 0; i < BOARD_EXT_GPIOCHIPS; i++) {
|
||||||
|
if (chips[i].base == 0) {
|
||||||
|
chip = &chips[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* no free chips left */
|
||||||
|
if (chip == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* register chip */
|
||||||
|
chip->name = name;
|
||||||
|
chip->ops = ops;
|
||||||
|
chip->base = gpio_base_free;
|
||||||
|
chip->size = size;
|
||||||
|
chip->priv = priv;
|
||||||
|
|
||||||
|
gpio_base_free += size;
|
||||||
|
|
||||||
|
return (chip->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Init all registered gpiochips
|
||||||
|
* @details will call gpiochip init ops for all registered chips
|
||||||
|
* calles when OS is ready, so gpiochip can start threads, use drivers and so on.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int gpiochips_init(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int ret;
|
||||||
|
int pins_added = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < BOARD_EXT_GPIOCHIPS; i++) {
|
||||||
|
struct gpiochip *chip = &chips[i];
|
||||||
|
|
||||||
|
if (!chip->base)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (chip->ops->init)
|
||||||
|
ret = chip->ops->init(chip->priv);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
/* remove chip if it fails to init */
|
||||||
|
/* TODO: we will have a gap, is it ok? */
|
||||||
|
chip->base = 0;
|
||||||
|
} else {
|
||||||
|
pins_added += chip->size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pins_added;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set pin mode of gpiochip
|
||||||
|
* @details set pad mode for given pin.
|
||||||
|
* return -1 if driver does not implemet setPadMode ops
|
||||||
|
* else return value from gpiochip driver.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int gpiochips_setPadMode(brain_pin_e pin, int mode)
|
||||||
|
{
|
||||||
|
struct gpiochip *chip = gpiochip_find(pin);
|
||||||
|
|
||||||
|
if (!chip)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((chip->ops->setPadMode))
|
||||||
|
return chip->ops->setPadMode(chip->priv, pin - chip->base, mode);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set value to gpio of gpiochip
|
||||||
|
* @details actual output value depent on current gpiochip implementation
|
||||||
|
* for smart switch inactive supposed to be closed switch (no current flows)
|
||||||
|
* returns -1 in case of pin not belong to any gpio chip
|
||||||
|
* returns -1 in case of chip does not support seting output value (input only)
|
||||||
|
* else return value from gpiochip driver;
|
||||||
|
*/
|
||||||
|
|
||||||
|
int gpiochips_writePad(brain_pin_e pin, int value)
|
||||||
|
{
|
||||||
|
struct gpiochip *chip = gpiochip_find(pin);
|
||||||
|
|
||||||
|
if (!chip)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (chip->ops->writePad)
|
||||||
|
return chip->ops->writePad(chip->priv, pin - chip->base, value);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get value to gpio of gpiochip
|
||||||
|
* @details actual input value depent on current gpiochip implementation
|
||||||
|
* returns -1 in case of pin not belong to any gpio chip
|
||||||
|
* returns -1 in case of chip does not support getting output value (output only)
|
||||||
|
* else return value from gpiochip driver;
|
||||||
|
*/
|
||||||
|
|
||||||
|
int gpiochips_readPad(brain_pin_e pin)
|
||||||
|
{
|
||||||
|
struct gpiochip *chip = gpiochip_find(pin);
|
||||||
|
|
||||||
|
if (!chip)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (chip->ops->readPad)
|
||||||
|
return chip->ops->readPad(chip->priv, pin - chip->base);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get total pin count allocated for external gpio chips.
|
||||||
|
* @details Will also include unused pins for chips that was registred
|
||||||
|
* but later fails to init.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int gpiochips_get_total_pins(void)
|
||||||
|
{
|
||||||
|
return (gpio_base_free - EXT_GPIOS_FIRST);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* BOARD_EXT_GPIOCHIPS > 0 */
|
||||||
|
|
||||||
|
int getHwPinExt(unsigned int pin)
|
||||||
|
{
|
||||||
|
(void)pin;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *portNameExt(unsigned int pin)
|
||||||
|
{
|
||||||
|
(void)pin;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gpiochip_register(const char *name, struct gpiochip_ops *ops, size_t size, void *priv)
|
||||||
|
{
|
||||||
|
(void)name; (void)ops; (void)size; (void)priv;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gpiochips_init(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gpiochips_get_total_pins(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* BOARD_EXT_GPIOCHIPS > 0 */
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* gpio_ext.h
|
||||||
|
*
|
||||||
|
* Abstraction layer definitions for extrenal gpios
|
||||||
|
*
|
||||||
|
* @date Mar 8, 2019
|
||||||
|
* @author Andrey Gusakov, (c) 2019
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GPIO_EXT_H_
|
||||||
|
#define GPIO_EXT_H_
|
||||||
|
|
||||||
|
#if EFI_PROD_CODE
|
||||||
|
#include "board.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "rusefi_enums.h"
|
||||||
|
|
||||||
|
/*==========================================================================*/
|
||||||
|
/* Checks */
|
||||||
|
/*==========================================================================*/
|
||||||
|
|
||||||
|
#ifndef BOARD_EXT_GPIOCHIPS
|
||||||
|
#define BOARD_EXT_GPIOCHIPS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
struct gpiochip_ops {
|
||||||
|
int (*setPadMode)(void *data, unsigned int pin, int mode);
|
||||||
|
int (*writePad)(void *data, unsigned int pin, int value);
|
||||||
|
int (*readPad)(void *data, unsigned int pin);
|
||||||
|
int (*getDiag)(void *data, unsigned int pin);
|
||||||
|
int (*init)(void *data);
|
||||||
|
int (*deinit)(void *data);
|
||||||
|
};
|
||||||
|
|
||||||
|
int getHwPinExt(unsigned int pin);
|
||||||
|
const char *portNameExt(unsigned int pin);
|
||||||
|
|
||||||
|
/* register gpio cgip */
|
||||||
|
int gpiochip_register(const char *name, struct gpiochip_ops *ops, size_t size, void *priv);
|
||||||
|
|
||||||
|
/* gpio extenders subsystem init */
|
||||||
|
int gpiochips_init(void);
|
||||||
|
|
||||||
|
int gpiochips_setPadMode(brain_pin_e pin, int mode);
|
||||||
|
int gpiochips_writePad(brain_pin_e pin, int value);
|
||||||
|
int gpiochips_readPad(brain_pin_e pin);
|
||||||
|
|
||||||
|
/* return total number of external gpios */
|
||||||
|
int gpiochips_get_total_pins(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* GPIO_EXT_H_ */
|
|
@ -79,6 +79,7 @@ include $(PROJECT_DIR)/controllers/system/system.mk
|
||||||
include $(PROJECT_DIR)/controllers/sensors/sensors.mk
|
include $(PROJECT_DIR)/controllers/sensors/sensors.mk
|
||||||
include $(PROJECT_DIR)/controllers/trigger/trigger.mk
|
include $(PROJECT_DIR)/controllers/trigger/trigger.mk
|
||||||
include $(PROJECT_DIR)/hw_layer/hw_layer.mk
|
include $(PROJECT_DIR)/hw_layer/hw_layer.mk
|
||||||
|
include $(PROJECT_DIR)/hw_layer/drivers/drivers.mk
|
||||||
include $(PROJECT_DIR)/hw_layer/sensors/sensors.mk
|
include $(PROJECT_DIR)/hw_layer/sensors/sensors.mk
|
||||||
include test.mk
|
include test.mk
|
||||||
|
|
||||||
|
@ -94,6 +95,7 @@ CSRC = $(UTILSRC) \
|
||||||
$(CONTROLLERS_MATH_SRC) \
|
$(CONTROLLERS_MATH_SRC) \
|
||||||
$(CONTROLLERS_SENSORS_SRC) \
|
$(CONTROLLERS_SENSORS_SRC) \
|
||||||
$(ENGINES_SRC) \
|
$(ENGINES_SRC) \
|
||||||
|
$(HW_LAYER_DRIVERS_CORE) \
|
||||||
$(TEST_SRC_C)
|
$(TEST_SRC_C)
|
||||||
|
|
||||||
# C++ sources that can be compiled in ARM or THUMB mode depending on the global
|
# C++ sources that can be compiled in ARM or THUMB mode depending on the global
|
||||||
|
@ -155,6 +157,7 @@ INCDIR = . \
|
||||||
$(PROJECT_DIR)/hw_layer \
|
$(PROJECT_DIR)/hw_layer \
|
||||||
$(PROJECT_DIR)/hw_layer/algo \
|
$(PROJECT_DIR)/hw_layer/algo \
|
||||||
$(PROJECT_DIR)/hw_layer/sensors/ \
|
$(PROJECT_DIR)/hw_layer/sensors/ \
|
||||||
|
$(HW_LAYER_DRIVERS_INC) \
|
||||||
test_data_structures \
|
test_data_structures \
|
||||||
googletest/googlemock/include \
|
googletest/googlemock/include \
|
||||||
googletest/googletest \
|
googletest/googletest \
|
||||||
|
|
|
@ -53,4 +53,6 @@
|
||||||
|
|
||||||
#define EFI_ANALOG_SENSORS TRUE
|
#define EFI_ANALOG_SENSORS TRUE
|
||||||
|
|
||||||
|
#define BOARD_EXT_GPIOCHIPS 3
|
||||||
|
|
||||||
#endif /* EFIFEATURES_H_ */
|
#endif /* EFIFEATURES_H_ */
|
||||||
|
|
|
@ -28,5 +28,6 @@ TEST_SRC_CPP = unit_test_framework.cpp \
|
||||||
tests/test_sensors.cpp \
|
tests/test_sensors.cpp \
|
||||||
tests/test_pid_auto.cpp \
|
tests/test_pid_auto.cpp \
|
||||||
tests/test_accel_enrichment.cpp \
|
tests/test_accel_enrichment.cpp \
|
||||||
|
tests/test_gpiochip.cpp \
|
||||||
afm2mapConverter.cpp
|
afm2mapConverter.cpp
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,146 @@
|
||||||
|
/**
|
||||||
|
* @file test_gpiochip.cpp
|
||||||
|
*
|
||||||
|
* @date Mar 12, 2019
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "unit_test_framework.h"
|
||||||
|
#include "global.h"
|
||||||
|
#include "gpio/gpio_ext.h"
|
||||||
|
|
||||||
|
using ::testing::_;
|
||||||
|
|
||||||
|
static int testchip_readPad(void *data, unsigned int pin)
|
||||||
|
{
|
||||||
|
if (pin & 0x01)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int io_state = 0;
|
||||||
|
|
||||||
|
static int testchip_writePad(void *data, unsigned int pin, int value)
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
io_state |= (1 << value);
|
||||||
|
else
|
||||||
|
io_state &= ~(1 << value);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int initcalls = 0;
|
||||||
|
|
||||||
|
static int testchip_init(void *data)
|
||||||
|
{
|
||||||
|
initcalls++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int calls_to_failed_chip = 0;
|
||||||
|
static int testchip_failed_writePad(void *data, unsigned int pin, int value)
|
||||||
|
{
|
||||||
|
calls_to_failed_chip++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int testchip_failed_init(void *data)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* invalid chip */
|
||||||
|
struct gpiochip_ops testchip0 = {
|
||||||
|
/*.setPadMode =*/ NULL,
|
||||||
|
/*.writePad =*/ NULL,
|
||||||
|
/*.readPad =*/ NULL,
|
||||||
|
/*.getDiag =*/ NULL,
|
||||||
|
/*.init =*/ testchip_init,
|
||||||
|
/*.deinit =*/ NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Input only chip */
|
||||||
|
struct gpiochip_ops testchip1 = {
|
||||||
|
/*.setPadMode =*/ NULL,
|
||||||
|
/*.writePad =*/ NULL,
|
||||||
|
/*.readPad =*/ testchip_readPad,
|
||||||
|
/*.getDiag =*/ NULL,
|
||||||
|
/*.init =*/ testchip_init,
|
||||||
|
/*.deinit =*/ NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Input only chip */
|
||||||
|
struct gpiochip_ops testchip2 = {
|
||||||
|
/*.setPadMode =*/ NULL,
|
||||||
|
/*.writePad =*/ testchip_writePad,
|
||||||
|
/*.readPad =*/ NULL,
|
||||||
|
/*.getDiag =*/ NULL,
|
||||||
|
/*.init =*/ testchip_init,
|
||||||
|
/*.deinit =*/ NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* testchi[ failed to init */
|
||||||
|
struct gpiochip_ops testchip3 = {
|
||||||
|
/*.setPadMode =*/ NULL,
|
||||||
|
/*.writePad =*/ testchip_failed_writePad,
|
||||||
|
/*.readPad =*/ NULL,
|
||||||
|
/*.getDiag =*/ NULL,
|
||||||
|
/*.init =*/ testchip_failed_init,
|
||||||
|
/*.deinit =*/ NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(gpioext, testGpioExt) {
|
||||||
|
int ret;
|
||||||
|
int chip1_base, chip2_base, chip3_base;
|
||||||
|
|
||||||
|
printf("====================================================================================== testGpioExt\r\n");
|
||||||
|
|
||||||
|
/* should fail to register chip with no readPad and writePad */
|
||||||
|
EXPECT_FALSE(gpiochip_register("invalid", &testchip0, 16, NULL) > 0);
|
||||||
|
|
||||||
|
/* should fail to register chip with zero gpios */
|
||||||
|
EXPECT_FALSE(gpiochip_register("invalid", &testchip1, 0, NULL) > 0);
|
||||||
|
|
||||||
|
chip1_base = gpiochip_register("input only", &testchip1, 16, NULL);
|
||||||
|
EXPECT_TRUE(chip1_base > 0);
|
||||||
|
|
||||||
|
EXPECT_EQ(16, gpiochips_get_total_pins());
|
||||||
|
|
||||||
|
chip2_base = gpiochip_register("output only", &testchip2, 16, NULL);
|
||||||
|
EXPECT_TRUE(chip2_base > 0);
|
||||||
|
|
||||||
|
/* this chip will fail to init, but should be registered without errors */
|
||||||
|
chip3_base = gpiochip_register("failed chip", &testchip3, 16, NULL);
|
||||||
|
EXPECT_TRUE(chip2_base > 0);
|
||||||
|
|
||||||
|
EXPECT_EQ(48, gpiochips_get_total_pins());
|
||||||
|
|
||||||
|
/* init 3 chips, one will fail */
|
||||||
|
ret = gpiochips_init();
|
||||||
|
EXPECT_EQ(32, ret);
|
||||||
|
|
||||||
|
/* two drivers should be inited */
|
||||||
|
EXPECT_EQ(2, initcalls);
|
||||||
|
|
||||||
|
/* gpio reads */
|
||||||
|
EXPECT_TRUE(gpiochips_readPad(chip1_base + 0) == 0);
|
||||||
|
EXPECT_TRUE(gpiochips_readPad(chip1_base + 1) != 0);
|
||||||
|
|
||||||
|
/* gpio write */
|
||||||
|
gpiochips_writePad(chip2_base + 0, 0);
|
||||||
|
gpiochips_writePad(chip2_base + 1, 1);
|
||||||
|
EXPECT_EQ(0x02, io_state);
|
||||||
|
|
||||||
|
/* try to access failed chip */
|
||||||
|
EXPECT_FALSE(gpiochips_writePad(chip3_base + 0, 0) >= 0);
|
||||||
|
EXPECT_FALSE(gpiochips_writePad(chip3_base + 1, 1) >= 0);
|
||||||
|
EXPECT_EQ(0, calls_to_failed_chip);
|
||||||
|
|
||||||
|
/* read/write outside range */
|
||||||
|
EXPECT_TRUE(gpiochips_readPad(chip1_base - 1) < 0);
|
||||||
|
EXPECT_TRUE(gpiochips_writePad(chip1_base - 1, 1) < 0);
|
||||||
|
|
||||||
|
EXPECT_TRUE(gpiochips_readPad(chip3_base + 16) < 0);
|
||||||
|
EXPECT_TRUE(gpiochips_writePad(chip3_base + 16, 1) < 0);
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue