ruuvi.drivers.c  ${PROJECT_VERSION}
Drivers for external sensors and peripherals on embedded systems.
ruuvi_interface_gpio_interrupt_test.c
Go to the documentation of this file.
2 #if RUUVI_RUN_TESTS
3 #include "ruuvi_driver_error.h"
4 #include "ruuvi_driver_test.h"
5 #include "ruuvi_interface_gpio.h"
9 #include <stdlib.h>
10 
11 static uint8_t num_int_trigs = 0;
12 static ri_gpio_evt_t last_evt;
13 
14 void on_interrupt (ri_gpio_evt_t evt)
15 {
16  num_int_trigs ++;
17  last_evt = evt;
18 }
19 
20 
30  const rd_test_gpio_cfg_t cfg)
31 {
32  rd_status_t status = RD_SUCCESS;
33  const uint8_t interrupt_table_size = RI_GPIO_INTERRUPT_TEST_TABLE_SIZE;
35 
36  if ( ( (cfg.input % 32) + ( (cfg.input >> 8) * 32)) > interrupt_table_size
37  || ( (cfg.output % 32) + ( (cfg.input >> 8) * 32)) > interrupt_table_size)
38  {
39  status |= RD_ERROR_NO_MEM;
40  }
41 
42  if (RD_SUCCESS == status)
43  {
44  // - Initialization must return @c RD_ERROR_INVALID_STATE if GPIO is uninitialized
45  status |= ri_gpio_uninit();
46  status |= ri_gpio_interrupt_init (interrupt_table, interrupt_table_size);
47 
48  if (RD_ERROR_INVALID_STATE != status)
49  {
50  RD_ERROR_CHECK (status, ~RD_ERROR_FATAL);
51  }
52  else
53  {
54  status = RD_SUCCESS;
55  }
56  }
57 
58  if (RD_SUCCESS == status)
59  {
60  // - Initialization must return @c RD_SUCCESS on first call.
61  status = ri_gpio_init();
62  status |= ri_gpio_interrupt_init (interrupt_table, interrupt_table_size);
63 
64  if (RD_SUCCESS != status)
65  {
66  RD_ERROR_CHECK (status, ~RD_ERROR_FATAL);
67  }
68  else
69  {
70  // - Initialization must return @c RD_ERROR_INVALID_STATE on second call.
71  status = ri_gpio_interrupt_init (interrupt_table, interrupt_table_size);
72 
73  if (RD_ERROR_INVALID_STATE != status)
74  {
75  RD_ERROR_CHECK (status, ~RD_ERROR_FATAL);
76  }
77 
78  // - Initialization must return @c RD_SUCCESS after uninitializtion.
79  status = ri_gpio_interrupt_uninit();
80  status |= ri_gpio_interrupt_init (interrupt_table, interrupt_table_size);
81 
82  if (RD_SUCCESS != status)
83  {
84  RD_ERROR_CHECK (status, ~RD_ERROR_FATAL);
85  return RD_ERROR_SELFTEST;
86  }
87  }
88  }
89 
90  if (RD_SUCCESS == status)
91  {
92  // - Initialization must return @c RD_ERROR_NULL if interrupt handler table is @c NULL.
93  status = ri_gpio_interrupt_init (NULL, interrupt_table_size);
94 
95  if (RD_ERROR_NULL != status)
96  {
97  RD_ERROR_CHECK (status, ~RD_ERROR_FATAL);
98  }
99  else
100  {
101  status = RD_SUCCESS;
102  }
103  }
104 
105  status |= ri_gpio_interrupt_uninit();
106  status |= ri_gpio_uninit();
107  return status;
108 }
109 
111  const rd_test_gpio_cfg_t cfg)
112 {
113  rd_status_t status = RD_SUCCESS;
114  const uint8_t interrupt_table_size = RI_GPIO_INTERRUPT_TEST_TABLE_SIZE;
116  interrupt_table[RI_GPIO_INTERRUPT_TEST_TABLE_SIZE] = {0};
117 
118  if ( ( (cfg.input % 32) + ( (cfg.input >> 8) * 32)) > interrupt_table_size
119  || ( (cfg.output % 32) + ( (cfg.input >> 8) * 32)) > interrupt_table_size)
120  {
121  return RD_ERROR_NO_MEM;
122  }
123 
124  // - Return RD_ERROR_INVALID_STATE if GPIO or GPIO_INTERRUPT are not initialized
126  ri_gpio_uninit();
127  status |= ri_gpio_interrupt_enable (cfg.input,
129 
130  if (RD_ERROR_INVALID_STATE != status)
131  {
132  RD_ERROR_CHECK (status, ~RD_ERROR_FATAL);
133  }
134  else
135  {
136  status = RD_SUCCESS;
137  }
138 
139  if (RD_SUCCESS == status)
140  {
141  // - Interrupt function shall be called exactly once when input is configured as low-to-high while input is low and
142  // input goes low-to-high, high-to-low.
143  num_int_trigs = 0;
144  status = ri_gpio_init();
145  status |= ri_gpio_interrupt_init (interrupt_table, interrupt_table_size);
146  status |= ri_gpio_configure (cfg.output,
148  status |= ri_gpio_write (cfg.output, RI_GPIO_LOW);
149  status |= ri_gpio_interrupt_enable (cfg.input,
151  status |= ri_gpio_write (cfg.output, RI_GPIO_HIGH);
152  status |= ri_gpio_write (cfg.output, RI_GPIO_LOW);
153 
154  if (RD_SUCCESS != status || 1 != num_int_trigs)
155  {
156  RD_ERROR_CHECK (status, ~RD_ERROR_FATAL);
157  status |= RD_ERROR_SELFTEST;
158  }
159  }
160 
161  if (RD_SUCCESS == status)
162  {
163  // - Interrupt function shall not be called after interrupt has been disabled
164  status |= ri_gpio_interrupt_disable (cfg.input);
165  status |= ri_gpio_write (cfg.output, RI_GPIO_HIGH);
166  status |= ri_gpio_write (cfg.output, RI_GPIO_LOW);
167 
168  if (RD_SUCCESS != status || 1 != num_int_trigs)
169  {
170  RD_ERROR_CHECK (status, ~RD_ERROR_FATAL);
171  status |= RD_ERROR_SELFTEST;
172  }
173 
174  // - Interrupt function maybe be called once or twice when input is configured as high-to-low while input is low and
175  // input goes low-to-high, high-to-low. i.e. Triggering during activation of test.
176  status |= ri_gpio_write (cfg.output, RI_GPIO_LOW);
177  num_int_trigs = 0;
178  status |= ri_gpio_interrupt_enable (cfg.input,
180  status |= ri_gpio_write (cfg.output, RI_GPIO_HIGH);
181  status |= ri_gpio_write (cfg.output, RI_GPIO_LOW);
182 
183  if (RD_SUCCESS != status
184  || ( (1 != num_int_trigs) && (2 != num_int_trigs)))
185  {
186  RD_ERROR_CHECK (status, ~RD_ERROR_FATAL);
187  status |= RD_ERROR_SELFTEST;
188  }
189 
190  // - Interrupt function shall be called exactly twice when input is configured as toggle while input is low and
191  // input goes low-to-high, high-to-low.
192  status = ri_gpio_write (cfg.output, RI_GPIO_LOW);
193  status |= ri_gpio_interrupt_disable (cfg.input);
194  num_int_trigs = 0;
195  status |= ri_gpio_interrupt_enable (cfg.input,
197  status |= ri_gpio_write (cfg.output, RI_GPIO_HIGH);
198  status |= ri_gpio_write (cfg.output, RI_GPIO_LOW);
199 
200  if (RD_SUCCESS != status || 2 != num_int_trigs)
201  {
202  RD_ERROR_CHECK (status, ~RD_ERROR_FATAL);
203  status |= RD_ERROR_SELFTEST;
204  }
205 
206  // - Interrupt pin shall be at logic HIGH when interrupt is enabled with a pull-up and the pin is not loaded externally
207  status = ri_gpio_configure (cfg.output,
209  status |= ri_gpio_interrupt_disable (cfg.input);
210  num_int_trigs = 0;
211  status |= ri_gpio_interrupt_enable (cfg.input,
213  ri_gpio_state_t state;
214  status |= ri_gpio_read (cfg.output, &state);
215 
216  if (RD_SUCCESS != status || RI_GPIO_HIGH != state)
217  {
218  RD_ERROR_CHECK (status, ~RD_ERROR_FATAL);
219  status |= RD_ERROR_SELFTEST;
220  }
221 
222  // - Interrupt pin shall be at logic LOW when interrupt is enabled with a pull-down and the pin is not loaded externally
224  status |= ri_gpio_interrupt_disable (cfg.input);
225  num_int_trigs = 0;
226  status |= ri_gpio_interrupt_enable (cfg.input,
228  on_interrupt);
229  status |= ri_gpio_read (cfg.output, &state);
230 
231  if (RD_SUCCESS != status || RI_GPIO_LOW != state)
232  {
233  RD_ERROR_CHECK (status, ~RD_ERROR_FATAL);
234  status |= RD_ERROR_SELFTEST;
235  }
236  }
237 
238  status |= ri_gpio_interrupt_disable (cfg.input);
239  status |= ri_gpio_interrupt_uninit();
240  status |= ri_gpio_uninit();
241  return status;
242 }
244  const ri_gpio_id_t input, const ri_gpio_id_t output)
245 {
246  rd_status_t status;
247  rd_test_gpio_cfg_t cfg;
248  cfg.input = input;
249  cfg.output = output;
250  printfp ("\"gpio_interrupt\":{\r\n");
251  printfp ("\"init\":");
252  status = ri_gpio_interrupt_test_init (cfg);
253 
254  if (RD_SUCCESS == status)
255  {
256  printfp ("\"pass\",\r\n");
257  }
258  else
259  {
260  printfp ("\"fail\",\r\n");
261  }
262 
263  printfp ("\"enable\":");
264  status = ri_gpio_interrupt_test_enable (cfg);
265 
266  if (RD_SUCCESS == status)
267  {
268  printfp ("\"pass\"\r\n");
269  }
270  else
271  {
272  printfp ("\"fail\"\r\n");
273  }
274 
275  printfp ("},\r\n");
276  return (RD_SUCCESS != status);
277 }
278 #endif
#define RD_ERROR_NULL
Null Pointer.
#define RD_ERROR_FATAL
Program should always reset after this.
uint32_t rd_status_t
bitfield for representing errors
#define RD_ERROR_CHECK(error, mask)
Shorthand macro for calling the rd_error_check with current file & line.
#define RD_SUCCESS
Internal Error.
#define RD_ERROR_NO_MEM
No Memory for operation.
#define RD_ERROR_SELFTEST
Self-test fail.
#define RD_ERROR_INVALID_STATE
Invalid state, operation disallowed in this state.
rd_status_t ri_gpio_uninit(void)
Uninitializes GPIO module. Call this to reset GPIO to High-Z mode. After uninitialization all GPIO pi...
rd_status_t ri_gpio_interrupt_enable(const ri_gpio_id_t pin, const ri_gpio_slope_t slope, const ri_gpio_mode_t mode, const ri_gpio_interrupt_fp_t handler)
Enable interrupt on a pin.
rd_status_t ri_gpio_interrupt_test_init(const rd_test_gpio_cfg_t cfg)
Test GPIO interrupt initialization.
rd_status_t ri_gpio_configure(const ri_gpio_id_t pin, const ri_gpio_mode_t mode)
Configure a pin of a port into a mode. If there are several ports the platform driver must implement ...
#define RI_GPIO_INTERRUPT_TEST_TABLE_SIZE
Fixed 64 interrupt table size, adjust this if some device has more than 2 ports with 32 gpios each.
rd_status_t ri_gpio_interrupt_init(ri_gpio_interrupt_fp_t *const interrupt_table, const uint16_t max_interrupts)
Initialize interrupt functionality to GPIO. Takes address of interrupt table as a pointer to avoid ty...
void(* ri_gpio_interrupt_fp_t)(const ri_gpio_evt_t)
rd_status_t ri_gpio_interrupt_test_enable(const rd_test_gpio_cfg_t cfg)
Test enabling interrupt on a pin.
rd_status_t ri_gpio_interrupt_uninit(void)
Uninitialize interrupt functionality of GPIO.
rd_status_t ri_gpio_interrupt_disable(const ri_gpio_id_t pin)
Disable interrupt on a pin.
rd_status_t ri_gpio_init(void)
Initializes GPIO module. Call this before other GPIO functions. After initialization all GPIO pins sh...
bool ri_gpio_interrupt_run_integration_test(const rd_test_print_fp printfp, const ri_gpio_id_t input, const ri_gpio_id_t output)
Run all GPIO interrupt integration tests.
rd_status_t ri_gpio_read(const ri_gpio_id_t pin, ri_gpio_state_t *const p_state)
Read state of a pin of a port into bool high If there are several ports the platform driver must impl...
rd_status_t ri_gpio_write(const ri_gpio_id_t pin, const ri_gpio_state_t state)
Write a pin of a port into given state If there are several ports the platform driver must implement ...
void(* rd_test_print_fp)(const char *const msg)
function pointer to print test information
Header to enable and disable module compilation.
Ruuvi error codes and error check function.
Functions for testing drivers.
uint16_t ri_gpio_id_t
port<<8 + pin
@ RI_GPIO_MODE_OUTPUT_STANDARD
Push-pull output, can be written.
@ RI_GPIO_MODE_INPUT_PULLUP
Input, can be read. Pulled up by internal resistor, value depends on IC.
@ RI_GPIO_MODE_INPUT_NOPULL
Input, can be read. No pull resistors.
@ RI_GPIO_MODE_INPUT_PULLDOWN
Input, can be read. Pulled dpwn by internal resistor, value depends on IC.
ri_gpio_state_t
States of GPIO pins.
@ RI_GPIO_LOW
GPIO electrically low.
@ RI_GPIO_HIGH
GPIO electrically high.
structure to configure GPIO test with input and output. These GPIOs must be physically connected on b...
ri_gpio_id_t input
Input pin used in test. Must be interrupt-capable.
ri_gpio_id_t output
Output pin used in test. Must be PWM-capable.