Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers test_utils.h Source File

test_utils.h

00001 /*
00002  * Copyright (c) 2019, Arm Limited and affiliates.
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  * http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 #ifndef TEST_UTILS_H
00019 #define TEST_UTILS_H
00020 
00021 #include <list>
00022 
00023 // test function prototypes
00024 typedef void (*TF1)(PinName p0);
00025 typedef void (*TF2)(PinName p0, PinName p1);
00026 typedef void (*TF3)(PinName p0, PinName p1, PinName p2);
00027 typedef void (*TF4)(PinName p0, PinName p1, PinName p2, PinName p3);
00028 typedef void (*TF5)(PinName p0, PinName p1, PinName p2, PinName p3, PinName p4);
00029 
00030 template<typename PortType, typename FunctionType, FunctionType f>
00031 struct FunctionCaller {
00032 
00033 };
00034 
00035 template<typename PortType, TF1 f>
00036 struct FunctionCaller<PortType, TF1, f> {
00037     void operator()(PortType &port)
00038     {
00039         f(port.pins[0]);
00040     }
00041 };
00042 
00043 template<typename PortType, TF2 f>
00044 struct FunctionCaller<PortType, TF2, f> {
00045     void operator()(PortType &port)
00046     {
00047         f(port.pins[0], port.pins[1]);
00048     }
00049 };
00050 
00051 template<typename PortType, TF3 f>
00052 struct FunctionCaller<PortType, TF3, f> {
00053     void operator()(PortType &port)
00054     {
00055         f(port.pins[0], port.pins[1], port.pins[2]);
00056     }
00057 };
00058 
00059 template<typename PortType, TF4 f>
00060 struct FunctionCaller<PortType, TF4, f> {
00061     void operator()(PortType &port)
00062     {
00063         f(port.pins[0], port.pins[1], port.pins[2], port.pins[3]);
00064     }
00065 };
00066 
00067 template<typename PortType, TF5 f>
00068 struct FunctionCaller<PortType, TF5, f> {
00069     void operator()(PortType &port)
00070     {
00071         f(port.pins[0], port.pins[1], port.pins[2], port.pins[3], port.pins[4]);
00072     }
00073 };
00074 
00075 template <typename PortType>
00076 bool peripheral_comparator(const PortType &port1, const PortType &port2)
00077 {
00078     return port1.peripheral == port2.peripheral;
00079 }
00080 
00081 template <typename PortType>
00082 bool peripheral_less(const PortType &port1, const PortType &port2)
00083 {
00084     return port1.peripheral < port2.peripheral;
00085 }
00086 
00087 template<typename PortType, typename FormFactorType>
00088 static bool find_port_pins(PortType &port)
00089 {
00090     return pinmap_find_peripheral_pins(FormFactorType::pins(), FormFactorType::restricted_pins(),
00091                                        port.peripheral, PortType::PinMap::maps, port.ppins, PortType::pin_count);
00092 }
00093 
00094 template<typename PortType, typename FormFactorType>
00095 void find_ports(std::list<PortType> &matched_ports, std::list<PortType> &not_matched_ports)
00096 {
00097     // Loop through every pin type
00098     for (uint32_t i = 0; i < PortType::pin_count; i++) {
00099         const PinMap *map = PortType::PinMap::maps[i];
00100         const char *pin_type = PortType::PinMap::pin_type_names[i];
00101 
00102         // Loop through each pin of a given type
00103         for (; map->pin != NC; map++) {
00104             PortType port;
00105             // Set pin being tested
00106             port.pins[i] = map->pin;
00107             port.peripheral = map->peripheral;
00108             // Only form factor pins can be tested
00109             if (!pinmap_list_has_pin(FormFactorType::pins(), port.pins[i])) {
00110                 continue;
00111             }
00112             // Don't test restricted pins
00113             if (pinmap_list_has_pin(FormFactorType::restricted_pins(), port.pins[i])) {
00114                 utest_printf("Skipping %s pin %s (%i)\r\n", pin_type,
00115                              FormFactorType::pin_to_string(port.pins[i]), port.pins[i]);
00116                 continue;
00117             }
00118             if (pinmap_list_has_peripheral(pinmap_restricted_peripherals(), port.peripheral)) {
00119                 utest_printf("Skipping %s peripheral %i with pin %s (%i)\r\n", pin_type,
00120                              port.peripheral, FormFactorType::pin_to_string(port.pins[i]), port.pins[i]);
00121                 continue;
00122             }
00123             // skipp pin searching if single pin port type
00124             if (PortType::pin_count > 1) {
00125                 find_port_pins<PortType, FormFactorType>(port);
00126             }
00127             if (port.empty()) {
00128                 not_matched_ports.push_back(port);
00129             } else {
00130                 matched_ports.push_back(port);
00131             }
00132         }
00133     }
00134 }
00135 
00136 
00137 template<typename PortType, typename FormFactorType, typename FunctionType, FunctionType f>
00138 void test_all_ports(std::list<PortType> &matched_ports, std::list<PortType> &not_matched_ports)
00139 {
00140     typedef typename std::list<PortType>::iterator Iter;
00141     utest_printf("***Testing %s on all form factor ports***\n", PortType::PinMap::name);
00142     const PinList *ff_pins = FormFactorType::pins();
00143     FunctionCaller<PortType, FunctionType, f> call;
00144 
00145     if (matched_ports.empty() && not_matched_ports.empty()) {
00146         utest_printf("Could not find pins for %s testing \n", PortType::PinMap::name);
00147         return;
00148     }
00149 
00150     for (uint32_t i = 0; i < ff_pins->count; i++) {
00151         for (Iter it = matched_ports.begin(); it != matched_ports.end(); ++it) {
00152             PortType &port = *it;
00153             for (uint32_t j = 0; j < PortType::pin_count; j++) {
00154                 if (ff_pins->pins[i] == port.pins[j]) {
00155                     utest_printf("%3s - %s pin tested on port: %s...", FormFactorType::pin_to_string(ff_pins->pins[i]),
00156                                  PortType::PinMap::pin_type_names[j], port.str());
00157                     if (port.status == PortType::StatusNotTested) {
00158                         call(port);
00159                         port.status = PortType::StatusPass;
00160                     }
00161                     utest_printf("%s\n", port.status == PortType::StatusPass ? "succeeded" : "failed");
00162                     goto end_port_iteration;
00163                 }
00164             }
00165         }
00166         for (Iter it = not_matched_ports.begin(); it != not_matched_ports.end(); ++it) {
00167             PortType &port = *it;
00168             for (uint32_t j = 0; j < PortType::pin_count; j++) {
00169                 if (ff_pins->pins[i] == port.pins[j]) {
00170                     utest_printf("%3s - Could not find pins to test %s pin %s (%d)\n",
00171                                  FormFactorType::pin_to_string(ff_pins->pins[i]),
00172                                  PortType::PinMap::pin_type_names[j],
00173                                  FormFactorType::pin_to_string(ff_pins->pins[i]),
00174                                  ff_pins->pins[i]);
00175                     goto end_port_iteration;
00176                 }
00177             }
00178         }
00179 end_port_iteration:
00180         ;
00181     }
00182 }
00183 
00184 template<typename PortType, typename FunctionType, FunctionType f>
00185 void test_peripheral(PortType &port)
00186 {
00187     if (port.empty()) {
00188         utest_printf("%d - Could not find pins to test peripheral\n", port.peripheral);
00189     } else {
00190         utest_printf("%d - peripheral tested on port: %s...", port.peripheral, port.str());
00191         if (port.status == PortType::StatusNotTested) {
00192             FunctionCaller<PortType, FunctionType, f> call;
00193             call(port); // run test
00194             port.status = PortType::StatusPass;
00195         }
00196         utest_printf("%s\n", port.status == PortType::StatusPass ? "succeeded" : "failed");
00197     }
00198 }
00199 
00200 template<typename PortType, typename FunctionType, FunctionType f>
00201 void test_all_peripherals(std::list<PortType> &matched_ports, std::list<PortType> &not_matched_ports)
00202 {
00203     typedef typename std::list<PortType>::iterator Iter;
00204     utest_printf("***Testing all %s peripherals***\n", PortType::PinMap::name);
00205 
00206     if (matched_ports.empty() && not_matched_ports.empty()) {
00207         utest_printf("Could not find pins for %s testing \n", PortType::PinMap::name);
00208         return;
00209     }
00210 
00211     matched_ports.sort(peripheral_less<PortType>);
00212     not_matched_ports.sort(peripheral_less<PortType>);
00213 
00214     for (Iter m_it = matched_ports.begin(), nm_it = not_matched_ports.begin();
00215             m_it != matched_ports.end() || nm_it != not_matched_ports.end();) {
00216         if (m_it != matched_ports.end() && nm_it != not_matched_ports.end()) {
00217             if ((*m_it).peripheral < (*nm_it).peripheral) {
00218                 test_peripheral<PortType, FunctionType, f>(*m_it);
00219                 ++m_it;
00220             } else {
00221                 test_peripheral<PortType, FunctionType, f>(*nm_it);
00222                 ++nm_it;
00223             }
00224         } else if (m_it != matched_ports.end()) {
00225             test_peripheral<PortType, FunctionType, f>(*m_it);
00226             ++m_it;
00227         } else if (nm_it != not_matched_ports.end()) {
00228             test_peripheral<PortType, FunctionType, f>(*nm_it);
00229             ++nm_it;
00230         }
00231     }
00232 }
00233 
00234 /**
00235  * Test function for all pinouts of all peripherals of a given type
00236  *
00237  * This template function takes in three template parameters:
00238  * - PortType - The type of peripheral to test
00239  * - FormFactorType - The form factor to test on
00240  * - f - The test function to run.
00241  *
00242  * This function calls the test function multiple times with
00243  * the appropriate combinations of pins.
00244  */
00245 template<typename PortType, typename FormFactorType, typename PortType::TestFunctionType f>
00246 void all_ports()
00247 {
00248     std::list<PortType> matched_ports, not_matched_ports;
00249     find_ports<PortType, FormFactorType>(matched_ports, not_matched_ports);
00250     matched_ports.unique();
00251     not_matched_ports.unique();
00252     test_all_ports<PortType, FormFactorType, typename PortType::TestFunctionType, f>(matched_ports, not_matched_ports);
00253 }
00254 
00255 /**
00256  * Test function for one pinout of all peripherals of a given type
00257  *
00258  * This template function takes in three template parameters:
00259  * - PortType - The type of peripheral to test
00260  * - FormFactorType - The form factor to test on
00261  * - f - The test function to run.
00262  *
00263  * This function calls the test function once for each peripheral
00264  * of the given type.
00265  */
00266 template<typename PortType, typename FormFactorType, typename PortType::TestFunctionType f>
00267 void all_peripherals()
00268 {
00269     std::list<PortType> matched_ports, not_matched_ports;
00270     find_ports<PortType, FormFactorType>(matched_ports, not_matched_ports);
00271 
00272     matched_ports.sort(peripheral_less<PortType>);
00273     not_matched_ports.sort(peripheral_less<PortType>);
00274     matched_ports.unique(peripheral_comparator<PortType>);
00275     not_matched_ports.unique(peripheral_comparator<PortType>);
00276 
00277     test_all_peripherals<PortType, typename PortType::TestFunctionType, f>(matched_ports, not_matched_ports);
00278 }
00279 
00280 /**
00281  * Test function for one pinout of one peripheral of a given type
00282  *
00283  * This template function takes in three template parameters:
00284  * - PortType - The type of peripheral to test
00285  * - FormFactorType - The form factor to test on
00286  * - f - The test function to run.
00287  *
00288  * This function calls the test function once for one peripheral
00289  * of the given type.
00290  */
00291 template<typename PortType, typename FormFactorType, typename PortType::TestFunctionType f>
00292 void one_peripheral()
00293 {
00294     std::list<PortType> matched_ports, not_matched_ports;
00295     find_ports<PortType, FormFactorType>(matched_ports, not_matched_ports);
00296 
00297     utest_printf("***Testing one %s pin configuration***\n", PortType::PinMap::name);
00298     if (matched_ports.empty()) {
00299         utest_printf("Could not find pins for %s testing \n", PortType::PinMap::name);
00300     } else {
00301         test_peripheral<PortType, typename PortType::TestFunctionType, f>(matched_ports.front());
00302     }
00303 }
00304 
00305 template <uint32_t N, typename PinMapType, typename FormFactorType, typename TestFunctionType>
00306 class Port;
00307 
00308 template <uint32_t N, typename PinMapType, typename FormFactorType, typename TestFunctionType>
00309 bool operator== (const Port<N, PinMapType, FormFactorType, TestFunctionType> &port1,
00310                  const Port<N, PinMapType, FormFactorType, TestFunctionType> &port2);
00311 
00312 template <uint32_t N, typename PinMapType, typename FormFactorType, typename FunctionType>
00313 class Port {
00314 public:
00315     int peripheral;
00316     PinName pins[N];
00317     PinName *ppins[N];
00318 
00319     static const uint32_t pin_count = N;
00320     typedef PinMapType PinMap;
00321     typedef FunctionType TestFunctionType;
00322 
00323     enum Status { StatusPass, StatusFail, StatusNotTested };
00324     Status status;
00325 
00326     Port(): peripheral(NC), status(StatusNotTested)
00327     {
00328         init_pins();
00329     }
00330 
00331     Port(const Port &port)
00332     {
00333         init_pins();
00334         copy_from(port);
00335     }
00336 
00337     void init_pins()
00338     {
00339         for (uint32_t i = 0; i < N; i++) {
00340             pins[i] = NC;
00341             ppins[i] = &pins[i];
00342         }
00343     }
00344 
00345     void copy_from(const Port &port)
00346     {
00347         peripheral = port.peripheral;
00348         status = port.status;
00349         for (uint32_t i = 0; i < N; i++) {
00350             pins[i] = port.pins[i];
00351         }
00352     }
00353 
00354     bool empty()
00355     {
00356         if (peripheral == NC) {
00357             return true;
00358         }
00359         for (uint32_t i = 0; i < N; i++) {
00360             if (pins[i] == NC) {
00361                 return true;
00362             }
00363         }
00364         return false;
00365     }
00366 
00367     const char *str()
00368     {
00369         static char port_str[128];
00370         char pin_str[32];
00371         sprintf(port_str, "peripheral=(%d) ", peripheral);
00372         for (uint32_t i = 0; i < N; i++) {
00373             sprintf(pin_str, "%s=(%s) ", PinMap::pin_type_names[i], FormFactorType::pin_to_string(pins[i]));
00374             strcat(port_str, pin_str);
00375         }
00376         return port_str;
00377     }
00378 
00379     friend bool operator==<> (const Port<N, PinMapType, FormFactorType, FunctionType> &port1, const Port<N, PinMapType, FormFactorType, FunctionType> &port2);
00380 };
00381 
00382 template <uint32_t N, typename PinMapType, typename FormFactorType, typename FunctionType>
00383 const uint32_t Port<N, PinMapType, FormFactorType, FunctionType>::pin_count;
00384 
00385 template <uint32_t N, typename PinMapType, typename FormFactorType, typename FunctionType>
00386 bool operator== (const Port<N, PinMapType, FormFactorType, FunctionType> &port1, const Port<N, PinMapType, FormFactorType, FunctionType> &port2)
00387 {
00388     if (port1.peripheral != port2.peripheral) {
00389         return false;
00390     }
00391     for (uint32_t i = 0; i < N; i++) {
00392         if (port1.pins[i] != port2.pins[i]) {
00393             return false;
00394         }
00395     }
00396     return true;
00397 }
00398 
00399 /**
00400  * This is a convenience class for use with the above templates
00401  *
00402  * This class can be passed as a template parameter to all_ports,
00403  * all_peripherals or one_peripheral to choose test pins from
00404  * the default form factor.
00405  */
00406 class DefaultFormFactor {
00407 public:
00408     static const PinList *pins()
00409     {
00410         return pinmap_ff_default_pins();
00411     }
00412 
00413     static const PinList *restricted_pins()
00414     {
00415         return pinmap_restricted_pins();
00416     }
00417 
00418     static const char *pin_to_string(PinName pin)
00419     {
00420         return pinmap_ff_default_pin_to_string(pin);
00421     }
00422 };
00423 
00424 /*
00425  * Peripheral port declarations are given below
00426  *
00427  * Each Port type represents a set of pins used by a peripheral.
00428  * The Port typedef is used as a template parameter to the functions
00429  * all_ports, all_peripherals and one_peripheral to select the peripheral
00430  * pin set to use for testing.
00431  */
00432 
00433 struct GPIOMaps {
00434     static const PinMap *maps[];
00435     static const char *const pin_type_names[];
00436     static const char *const name;
00437 };
00438 const PinMap *GPIOMaps::maps[] = { gpio_pinmap() };
00439 const char *const GPIOMaps::pin_type_names[] = { "IO" };
00440 const char *const GPIOMaps::name = "GPIO";
00441 typedef Port<1, GPIOMaps, DefaultFormFactor, TF1> GPIOPort;
00442 
00443 #if DEVICE_INTERRUPTIN
00444 #include "gpio_irq_api.h"
00445 struct GPIOIRQMaps {
00446     static const PinMap *maps[];
00447     static const char *const pin_type_names[];
00448     static const char *const name;
00449 };
00450 const PinMap *GPIOIRQMaps::maps[] = { gpio_irq_pinmap() };
00451 const char *const GPIOIRQMaps::pin_type_names[] = { "IRQ_IN" };
00452 const char *const GPIOIRQMaps::name = "GPIO_IRQ";
00453 typedef Port<1, GPIOIRQMaps, DefaultFormFactor, TF1> GPIOIRQPort;
00454 #endif
00455 
00456 #if DEVICE_SPI
00457 #include "spi_api.h"
00458 struct SPIMaps {
00459     static const PinMap *maps[];
00460     static const char *const pin_type_names[];
00461     static const char *const name;
00462 };
00463 const PinMap *SPIMaps::maps[] = { spi_master_mosi_pinmap(), spi_master_miso_pinmap(), spi_master_clk_pinmap(), spi_master_cs_pinmap() };
00464 const char *const SPIMaps::pin_type_names[] = { "MOSI", "MISO", "SCLK", "SSEL" };
00465 const char *const SPIMaps::name = "SPI";
00466 typedef Port<4, SPIMaps, DefaultFormFactor, TF4> SPIPort;
00467 
00468 struct SPINoCSMaps {
00469     static const PinMap *maps[];
00470     static const char *const pin_type_names[];
00471     static const char *const name;
00472 };
00473 const PinMap *SPINoCSMaps::maps[] = { spi_master_mosi_pinmap(), spi_master_miso_pinmap(), spi_master_clk_pinmap()};
00474 const char *const SPINoCSMaps::pin_type_names[] = { "MOSI", "MISO", "SCLK" };
00475 const char *const SPINoCSMaps::name = "SPI";
00476 typedef Port<3, SPINoCSMaps, DefaultFormFactor, TF3> SPINoCSPort;
00477 
00478 struct SPISlaveMaps {
00479     static const PinMap *maps[];
00480     static const char *const pin_type_names[];
00481     static const char *const name;
00482 };
00483 const PinMap *SPISlaveMaps::maps[] = { spi_slave_mosi_pinmap(), spi_slave_miso_pinmap(), spi_slave_clk_pinmap(), spi_slave_cs_pinmap() };
00484 const char *const SPISlaveMaps::pin_type_names[] = { "MOSI", "MISO", "SCLK", "SSEL" };
00485 const char *const SPISlaveMaps::name = "SPISlave";
00486 typedef Port<4, SPISlaveMaps, DefaultFormFactor, TF4> SPISlavePort;
00487 #endif
00488 
00489 #if DEVICE_I2C
00490 #include "i2c_api.h"
00491 struct I2CMaps {
00492     static const PinMap *maps[];
00493     static const char *const pin_type_names[];
00494     static const char *const name;
00495 };
00496 const PinMap *I2CMaps::maps[] = { i2c_master_sda_pinmap(), i2c_master_scl_pinmap() };
00497 const char *const I2CMaps::pin_type_names[] = { "SDA", "SCL" };
00498 const char *const I2CMaps::name = "I2C";
00499 typedef Port<2, I2CMaps, DefaultFormFactor, TF2> I2CPort;
00500 #endif
00501 
00502 #if DEVICE_PWMOUT
00503 #include "pwmout_api.h"
00504 struct PWMMaps {
00505     static const PinMap *maps[];
00506     static const char *const pin_type_names[];
00507     static const char *const name;
00508 };
00509 const PinMap *PWMMaps::maps[] = { pwmout_pinmap() };
00510 const char *const PWMMaps::pin_type_names[] = { "PWM_OUT" };
00511 const char *const PWMMaps::name = "PWM";
00512 typedef Port<1, PWMMaps, DefaultFormFactor, TF1> PWMPort;
00513 #endif
00514 
00515 #if DEVICE_ANALOGIN
00516 #include "analogin_api.h"
00517 struct AnaloginMaps {
00518     static const PinMap *maps[];
00519     static const char *const pin_type_names[];
00520     static const char *const name;
00521 };
00522 const PinMap *AnaloginMaps::maps[] = { analogin_pinmap() };
00523 const char *const AnaloginMaps::pin_type_names[] = { "ADC_IN" };
00524 const char *const AnaloginMaps::name = "ADC";
00525 typedef Port<1, AnaloginMaps, DefaultFormFactor, TF1> AnaloginPort;
00526 #endif
00527 
00528 #if DEVICE_ANALOGOUT
00529 #include "analogout_api.h"
00530 struct AnalogoutMaps {
00531     static const PinMap *maps[];
00532     static const char *const pin_type_names[];
00533     static const char *const name;
00534 };
00535 const PinMap *AnalogoutMaps::maps[] = { analogout_pinmap() };
00536 const char *const AnalogoutMaps::pin_type_names[] = { "DAC_OUT" };
00537 const char *const AnalogoutMaps::name = "DAC";
00538 typedef Port<1, AnalogoutMaps, DefaultFormFactor, TF1> AnalogoutPort;
00539 #endif
00540 
00541 #if DEVICE_SERIAL
00542 #if DEVICE_SERIAL_FC
00543 struct UARTMaps {
00544     static const PinMap *maps[];
00545     static const char *const pin_type_names[];
00546     static const char *const name;
00547 };
00548 const PinMap *UARTMaps::maps[] = { serial_tx_pinmap(), serial_rx_pinmap(), serial_cts_pinmap(), serial_rts_pinmap() };
00549 const char *const UARTMaps::pin_type_names[] = { "TX", "RX", "CLS", "RTS" };
00550 const char *const UARTMaps::name = "UART";
00551 typedef Port<4, UARTMaps, DefaultFormFactor, TF4> UARTPort;
00552 #endif
00553 
00554 struct UARTNoFCMaps {
00555     static const PinMap *maps[];
00556     static const char *const pin_type_names[];
00557     static const char *const name;
00558 };
00559 const PinMap *UARTNoFCMaps::maps[] = { serial_tx_pinmap(), serial_rx_pinmap() };
00560 const char *const UARTNoFCMaps::pin_type_names[] = { "TX", "RX" };
00561 const char *const UARTNoFCMaps::name = "UART-no-FC";
00562 typedef Port<2, UARTNoFCMaps, DefaultFormFactor, TF2> UARTNoFCPort;
00563 #endif
00564 
00565 #endif