From 63d89124a158929ec6f5d11b8dd742afee4fe7fd Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz Date: Tue, 5 Dec 2023 16:30:35 -0300 Subject: [PATCH 1/3] CI: Add peripheral manager test --- tests/periman/periman.ino | 294 ++++++++++++++++++++++++++++++++++ tests/periman/test_periman.py | 26 +++ 2 files changed, 320 insertions(+) create mode 100644 tests/periman/periman.ino create mode 100644 tests/periman/test_periman.py diff --git a/tests/periman/periman.ino b/tests/periman/periman.ino new file mode 100644 index 00000000000..91a88e01599 --- /dev/null +++ b/tests/periman/periman.ino @@ -0,0 +1,294 @@ +/* Peripheral Manager test + * + * This test is using Serial to check if the peripheral manager is able to + * attach and detach peripherals correctly on shared pins. + * Make sure that the peripheral names contain only letters, numbers and underscores. + * + * This test skips the following peripherals: + * - USB: USB is not able to be detached + * - SDMMC: SDMMC requires a card to be mounted before the pins are attached + * - ETH: ETH requires a ethernet port to be connected before the pins are attached + */ + +#if SOC_I2S_SUPPORTED +#include "ESP_I2S.h" +#endif + +#if SOC_I2C_SUPPORTED +#include "Wire.h" +#endif + +#if SOC_GPSPI_SUPPORTED +#include "SPI.h" +#endif + +/* Definitions */ + +#define UART1_RX_DEFAULT 4 +#define UART1_TX_DEFAULT 5 + +#define ADC1_DEFAULT A4 + +#if CONFIG_IDF_TARGET_ESP32 +# define ADC2_DEFAULT A5 +#else +# define ADC2_DEFAULT A3 +#endif + +#if CONFIG_IDF_TARGET_ESP32 +# define TOUCH1_DEFAULT T0 +# define TOUCH2_DEFAULT T2 +#else +# define TOUCH1_DEFAULT T4 +# define TOUCH2_DEFAULT T5 +#endif + +/* Global variables */ + +bool test_executed = false; +String current_test; +int8_t uart1_rx_pin; +int8_t uart1_tx_pin; + +/* Callback functions */ + +void onReceive_cb(void) { + // This is a callback function that will be activated on UART RX events + size_t available = Serial1.available(); + while (available --) { + Serial.print((char)Serial1.read()); + } +} + +// This function is called by before each test is run +void setup_test(String test_name, int8_t rx_pin = UART1_RX_DEFAULT, int8_t tx_pin = UART1_TX_DEFAULT) { + log_v("Setting up %s test", test_name.c_str()); + + current_test = test_name; + uart1_rx_pin = rx_pin; + uart1_tx_pin = tx_pin; + test_executed = false; + + pinMode(uart1_rx_pin, INPUT_PULLUP); + pinMode(uart1_tx_pin, OUTPUT); + Serial1.setPins(uart1_rx_pin, uart1_tx_pin); + uart_internal_loopback(1, uart1_rx_pin); + delay(100); + log_v("Running %s test", test_name.c_str()); +} + +// This function is called after each test is run +void teardown_test(void) { + log_v("Tearing down %s test", current_test.c_str()); + if (test_executed) { + pinMode(uart1_rx_pin, INPUT_PULLUP); + pinMode(uart1_tx_pin, OUTPUT); + Serial1.print(current_test); + Serial1.println(" test: This should not be printed"); + Serial1.flush(); + + Serial1.setPins(uart1_rx_pin, uart1_tx_pin); + uart_internal_loopback(1, uart1_rx_pin); + delay(100); + } + + Serial1.print(current_test); + Serial1.println(" test: This should be printed"); + Serial1.flush(); + + log_v("Finished %s test", current_test.c_str()); +} + +/* Test functions */ +/* These functions must only init the peripheral on the same pins and update "current_test" */ + +void gpio_test(void) { + setup_test("GPIO"); + test_executed = true; + pinMode(uart1_rx_pin, INPUT); + pinMode(uart1_tx_pin, OUTPUT); + digitalRead(uart1_rx_pin); + digitalWrite(uart1_tx_pin, HIGH); + teardown_test(); +} + +void sigmadelta_test(void) { + setup_test("SigmaDelta"); +#if SOC_SDM_SUPPORTED + test_executed = true; + if (!sigmaDeltaAttach(uart1_rx_pin, 312500)) { + Serial.println("SigmaDelta init failed"); + } + if (!sigmaDeltaAttach(uart1_tx_pin, 312500)) { + Serial.println("SigmaDelta init failed"); + } +#endif + teardown_test(); +} + +void adc_oneshot_test(void) { +#if !SOC_ADC_SUPPORTED + setup_test("ADC_Oneshot"); +#else + setup_test("ADC_Oneshot", ADC1_DEFAULT, ADC2_DEFAULT); + test_executed = true; + analogReadResolution(12); + pinMode(ADC1_DEFAULT, INPUT); + pinMode(ADC2_DEFAULT, INPUT); + analogRead(ADC1_DEFAULT); + analogRead(ADC2_DEFAULT); +#endif + teardown_test(); +} + +#if SOC_ADC_SUPPORTED +volatile bool adc_coversion_done = false; +void ARDUINO_ISR_ATTR adcComplete() { + adc_coversion_done = true; +} +#endif + +void adc_continuous_test(void) { +#if !SOC_ADC_SUPPORTED + setup_test("ADC_Continuous"); +#else + setup_test("ADC_Continuous", ADC1_DEFAULT, ADC2_DEFAULT); + test_executed = true; + uint8_t adc_pins[] = {ADC1_DEFAULT, ADC2_DEFAULT}; + uint8_t adc_pins_count = 2; + adc_continuos_data_t * result = NULL; + + analogContinuousSetWidth(12); + analogContinuousSetAtten(ADC_11db); + + analogContinuous(adc_pins, adc_pins_count, 6, 20000, &adcComplete); + analogContinuousStart(); + + while (adc_coversion_done == false) { + delay(1); + } + + if (!analogContinuousRead(&result, 0)) { + Serial.println("ADC continuous read failed"); + } + + analogContinuousStop(); +#endif + teardown_test(); +} + +void dac_test(void) { +#if !SOC_DAC_SUPPORTED + setup_test("DAC"); +#else + setup_test("DAC", DAC1, DAC2); + test_executed = true; + dacWrite(DAC1, 255); + dacWrite(DAC2, 255); +#endif + teardown_test(); +} + +void ledc_test(void) { + setup_test("LEDC"); +#if SOC_LEDC_SUPPORTED + test_executed = true; + if (!ledcAttach(uart1_rx_pin, 5000, 12)) { + Serial.println("LEDC init failed"); + } + if (!ledcAttach(uart1_tx_pin, 5000, 12)) { + Serial.println("LEDC init failed"); + } +#endif + teardown_test(); +} + +void rmt_test(void) { + setup_test("RMT"); +#if SOC_RMT_SUPPORTED + test_executed = true; + if (!rmtInit(uart1_rx_pin, RMT_TX_MODE, RMT_MEM_NUM_BLOCKS_1, 10000000)) { + Serial.println("RMT init failed"); + } + if (!rmtInit(uart1_tx_pin, RMT_RX_MODE, RMT_MEM_NUM_BLOCKS_1, 10000000)) { + Serial.println("RMT init failed"); + } +#endif + teardown_test(); +} + +void i2s_test(void) { + setup_test("I2S"); +#if SOC_I2S_SUPPORTED + test_executed = true; + I2SClass i2s; + + i2s.setPins(uart1_rx_pin, uart1_tx_pin, -1); + i2s.setTimeout(1000); + if (!i2s.begin(I2S_MODE_STD, 16000, I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO)) { + Serial.println("I2S init failed"); + } +#endif + teardown_test(); +} + +void i2c_test(void) { + setup_test("I2C"); +#if SOC_I2C_SUPPORTED + test_executed = true; + if (!Wire.begin(uart1_rx_pin, uart1_tx_pin)) { + Serial.println("I2C init failed"); + } +#endif + teardown_test(); +} + +void spi_test(void) { + setup_test("SPI"); +#if SOC_GPSPI_SUPPORTED + test_executed = true; + SPI.begin(uart1_rx_pin, uart1_tx_pin, -1, -1); +#endif + teardown_test(); +} + +void touch_test(void) { +#if !SOC_TOUCH_SENSOR_SUPPORTED + setup_test("Touch"); +#else + setup_test("Touch", TOUCH1_DEFAULT, TOUCH2_DEFAULT); + test_executed = true; + touchRead(TOUCH1_DEFAULT); + touchRead(TOUCH2_DEFAULT); +#endif + teardown_test(); +} + +/* Main functions */ + +void setup() { + Serial.begin(115200); + while(!Serial) { delay(10); } + + Serial1.setPins(UART1_RX_DEFAULT, UART1_TX_DEFAULT); + Serial1.begin(115200); + while(!Serial1) { delay(10); } + Serial1.onReceive(onReceive_cb); + uart_internal_loopback(1, uart1_rx_pin); + + gpio_test(); + sigmadelta_test(); + ledc_test(); + rmt_test(); + i2s_test(); + i2c_test(); + spi_test(); + adc_oneshot_test(); + adc_continuous_test(); + dac_test(); + touch_test(); + + Serial1.println("Peripheral Manager test done"); +} + +void loop() {} diff --git a/tests/periman/test_periman.py b/tests/periman/test_periman.py new file mode 100644 index 00000000000..4bce226bfad --- /dev/null +++ b/tests/periman/test_periman.py @@ -0,0 +1,26 @@ +def test_periman(dut): + peripherals = ["GPIO", "SigmaDelta", "LEDC", "RMT", "I2S", "I2C", "SPI", + "ADC_Oneshot", "ADC_Continuous", "DAC", "Touch"] + + pattern = rb"(?:\b\w+\b test: This should(?: not)? be printed|Peripheral Manager test done)" + + while True: + try: + res = dut.expect(pattern, timeout=10) + except: + assert False, f"Could not detect end of test" + + console_output = res.group(0).decode("utf-8") + peripheral = console_output.split()[0] + + if "Peripheral Manager test done" in console_output: + break + + if peripheral in peripherals: + if "not" in console_output: + assert False, f"Peripheral {peripheral} printed when it should not" + peripherals.remove(peripheral) + else: + assert False, f"Unknown peripheral: {peripheral}" + + assert peripherals == [], f"Missing peripherals output: {peripherals}" From a59546f28e7228a333272d4e278df46b7d307e2e Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz Date: Tue, 5 Dec 2023 16:32:23 -0300 Subject: [PATCH 2/3] Add note --- tests/periman/periman.ino | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/periman/periman.ino b/tests/periman/periman.ino index 91a88e01599..eeb426c09ab 100644 --- a/tests/periman/periman.ino +++ b/tests/periman/periman.ino @@ -288,6 +288,7 @@ void setup() { dac_test(); touch_test(); + // Print to Serial1 to avoid buffering issues Serial1.println("Peripheral Manager test done"); } From 570551bdf05d1bb8ce84c483dfc7ef724d728ea9 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz Date: Wed, 6 Dec 2023 09:38:05 -0300 Subject: [PATCH 3/3] Update comment --- tests/periman/periman.ino | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/periman/periman.ino b/tests/periman/periman.ino index eeb426c09ab..dd9d61724a9 100644 --- a/tests/periman/periman.ino +++ b/tests/periman/periman.ino @@ -100,7 +100,9 @@ void teardown_test(void) { } /* Test functions */ -/* These functions must only init the peripheral on the same pins and update "current_test" */ +/* These functions must call "setup_test" and "teardown_test" and set "test_executed" to true + * if the test is executed + */ void gpio_test(void) { setup_test("GPIO");