param_test.h 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /*
  2. * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. /*
  7. * Parameterized Test Framework
  8. *
  9. * Peripherals like SPI has several parameters like: freq, mode, DMA, etc.
  10. * This framework helps to test different parameter sets with the same program.
  11. *
  12. * Each "parameter set" is a set with different parameters (freq, mode, etc.).
  13. * A parameter group is a group of several parameter sets. Each unit test performs
  14. * tests among the sets in a group.
  15. *
  16. * The test will be execute in the following sequence:
  17. * 1. ``pre_test``: initialize the context
  18. * 2. take a set out of the parameter group
  19. * 3. ``def_param``: fill in default value for the parameter set if not set
  20. * 4. ``loop``: execute test program for the set in the initialized context
  21. * 5. loop executing 2-4 until the last set
  22. * 6. ``post_test``: free the resources used.
  23. *
  24. * Usage example:
  25. *
  26. * 1. Define your own parameter set type:
  27. * typedef struct {
  28. * const char pset_name[PSET_NAME_LEN];
  29. * //The test work till the frequency below,
  30. * //set the frequency to higher and remove checks in the driver to know how fast the system can run.
  31. * const int *freq_list; // list of tested frequency, terminated by 0
  32. * int freq_limit; //freq larger (not equal) than this will be ignored
  33. * spi_dup_t dup;
  34. * int mode;
  35. * bool length_aligned;
  36. * int test_size;
  37. *
  38. * int master_limit; // the master disable dummy bits and discard readings over this freq
  39. * bool master_iomux;
  40. * int master_dma_chan;
  41. *
  42. * bool slave_iomux;
  43. * int slave_dma_chan;
  44. * int slave_tv_ns;
  45. * bool slave_unaligned_addr;
  46. * } spitest_param_set_t;
  47. *
  48. * 2. Define a parameter set:
  49. * spitest_param_set_t mode_pgroup[] = {
  50. * //non-DMA tests
  51. * { .pset_name = "mode 0, no DMA",
  52. * .freq_list = test_freq_mode,
  53. * .master_limit = FREQ_LIMIT_MODE,
  54. * .dup = FULL_DUPLEX,
  55. * .master_iomux= true,
  56. * .slave_iomux = true,
  57. * .slave_tv_ns = TV_WITH_ESP_SLAVE,
  58. * .mode = 0,
  59. * },
  60. * { .pset_name = "mode 1, no DMA",
  61. * .freq_list = test_freq_mode,
  62. * .master_limit = FREQ_LIMIT_MODE,
  63. * .dup = FULL_DUPLEX,
  64. * .master_iomux= true,
  65. * .slave_iomux = true,
  66. * .slave_tv_ns = TV_WITH_ESP_SLAVE,
  67. * .mode = 1,
  68. * },
  69. * // other configurations...
  70. * };
  71. *
  72. * 3. Define your test functions, and wrap them in the ``param_test_func_t``:
  73. * static const param_test_func_t master_test_func = {
  74. * .pre_test = test_master_init,
  75. * .post_test = test_master_deinit,
  76. * .loop = test_master_loop,
  77. * .def_param = spitest_def_param,
  78. * };
  79. *
  80. * 4. Declare the group by PARAM_GROUP_DECLARE right after the param group:
  81. * PARAM_GROUP_DECLARE(MODE, mode_pgroup)
  82. *
  83. * 5. Declare the test function by TEST_SINGLE_BOARD (for single board test), or TEST_MASTER_SLAVE(for multiboard test)
  84. * TEST_MASTER_SLAVE(MODE, mode_pgroup, "[spi][timeout=120]", &master_test_func, &slave_test_func)
  85. *
  86. * or
  87. * TEST_SINGLE_BOARD(TIMING, timing_pgroup, "[spi][timeout=120]", &local_test_func)
  88. *
  89. * NOTE: suggest to define your own macro to wrap 4 and 5 if your tag and test functions are the same. E.g.:
  90. * #define TEST_SPI_MASTER_SLAVE(name, pgroup) (backslash)
  91. * PARAM_GROUP_DECLARE(name, pgroup) (backslash)
  92. * TEST_MASTER_SLAVE(name, pgroup, "[spi][timeout=120]", &master_test_func, &slave_test_func)
  93. *
  94. * Then declare tests conveniently by:
  95. * TEST_SPI_MASTER_SLAVE(TIMING, timing_pgroup)
  96. * TEST_SPI_MASTER_SLAVE(MODE, mode_pgroup)
  97. *
  98. */
  99. #define PGROUP_NAME_LEN 20 ///< name length of parameter group
  100. #define PGROUP_NAME(name) PGROUP_##name ///< param group name
  101. #define PTEST_MASTER_NAME(name) PTEST_MASTER_##name ///< test function name of master
  102. #define PTEST_SLAVE_NAME(name) PTEST_SLAVE_##name ///< test function name of slave
  103. /// Test set structure holding name, param set array pointer, item size and param set num.
  104. typedef struct {
  105. char name[PGROUP_NAME_LEN]; ///< Name of param group to print
  106. void *param_group; ///< Start of the param group array
  107. int pset_size; ///< Size of each param set
  108. int pset_num; ///< Total number of param sets
  109. } param_group_t;
  110. /// Test functions for the frameowrk
  111. typedef struct {
  112. void (*pre_test)(void** contxt); ///< Initialization function called before tests begin. Initial your context here
  113. void (*post_test)(void* context); ///< Deinit function called after all tests are done.
  114. void (*def_param)(void* inout_pset); ///< Function to fill each pset structure before executed, left NULL if not used.
  115. void (*loop)(const void* pset, void* context); ///< Function execute each param set
  116. } ptest_func_t;
  117. /**
  118. * Test framework to execute init, loop and deinit.
  119. *
  120. * @param param_group Parameter group holder to test in turns.
  121. * @param test_func Function set to execute.
  122. */
  123. void test_serializer(const param_group_t *param_group, const ptest_func_t* test_func);
  124. #define PARAM_GROUP_DECLARE_TYPE(group_name, pset_type, pgroup) \
  125. static const param_group_t PGROUP_NAME(pgroup) = { \
  126. .name = #group_name, \
  127. .param_group = (void*)&pgroup, \
  128. .pset_size = sizeof(pset_type), \
  129. .pset_num = sizeof(pgroup)/sizeof(pset_type), \
  130. };
  131. /**
  132. * Declare parameter group
  133. *
  134. * @param group_name Parameter group name to print in the beginning of the test
  135. * @param param_group Parameter group structure, should be already defined above, and the size and type is defined.
  136. */
  137. #define PARAM_GROUP_DECLARE(group_name, param_group) \
  138. PARAM_GROUP_DECLARE_TYPE(group_name, typeof(param_group[0]), param_group)
  139. /**
  140. * Test parameter group on one board.
  141. *
  142. * @param name Test name to be printed in the menu.
  143. * @param param_group Parameter group to be tested.
  144. * @param tag Tag for environment, etc. e.g. [spi][timeout=120]
  145. * @param test_func ``ptest_func_t`` to be executed.
  146. */
  147. #define TEST_SINGLE_BOARD(name, param_group, tag, test_func) \
  148. TEST_CASE("single board test: "#name, tag) { test_serializer(&PGROUP_NAME(param_group), test_func); }
  149. /**
  150. * Test parameter group for master-slave framework
  151. *
  152. * @param name Test name to be printed in the menu.
  153. * @param param_group Parameter group to be tested.
  154. * @param tag Tag for environment, etc. e.g. [spi][timeout=120]
  155. * @param master_func ``ptest_func_t`` to be executed by master.
  156. * @param slave_func ``ptest_func_t`` to be executed by slave.
  157. */
  158. #define TEST_MASTER_SLAVE(name, param_group, tag, master_func, slave_func) \
  159. static void PTEST_MASTER_NAME(name) (void) { test_serializer(&PGROUP_NAME(param_group), master_func); } \
  160. static void PTEST_SLAVE_NAME(name) (void) { test_serializer(&PGROUP_NAME(param_group), slave_func); } \
  161. TEST_CASE_MULTIPLE_DEVICES("master slave test: "#name, tag, PTEST_MASTER_NAME(name), PTEST_SLAVE_NAME(name))