Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added conconcurrent testing #62

Merged
merged 8 commits into from
Aug 7, 2017
217 changes: 217 additions & 0 deletions TESTS/concurrent/Comms/Comms.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
/*
* Copyright (c) 2016 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


#if !DEVICE_SPI // check if SPI is supported on this device
#error [NOT_SUPPORTED] SPI is not supported on this platform, add 'DEVICE_SPI' definition to your platform.

#elif !DEVICE_I2C // check if I2C is supported on this device
#error [NOT_SUPPORTED] I2C not supported on this platform, add 'DEVICE_I2C' definition to your platform.

#endif // !DEVICE_SPI or !DEVICE_I2C


#include "mbed.h"
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include "ci_test_config.h"
#include "FATFileSystem.h"
#include "SDBlockDevice.h"
#include <I2CEeprom.h>

using namespace utest::v1;

#define TEST_STRING_MAX 128

Thread Thread_I2C; // thread used in multithread tests
Thread Thread_SPI; // thread used in multithread tests
osThreadId Multi_Thread_ID; // thread id for main function controlling multithread tests
char Test_String[TEST_STRING_MAX] = {0}; // reference string used in testing

// Fill array with random characters. TODO: make this string a randomly generated thing
void init_string()
{
for(int x = 0; x < TEST_STRING_MAX-1; x++){
Test_String[x] = 'A' + (rand() % 26);
}
Test_String[TEST_STRING_MAX-1] = 0;

DEBUG_PRINTF("\r\n****\r\n Test_String Size(Bytes) = %d\r\n Test_String = %s\r\n****\r\n",TEST_STRING_MAX,Test_String);
}


// test I2C API by writting and reading from EEPROM
void test_I2C()
{
// initialize variables and API
int address = 0; // starting address to write to
int num_read = 0; // will report number of bytes read
int num_written = 0; // will report number of bytes written
volatile char read_string[TEST_STRING_MAX] = {0}; // string that will be updated from reading EEPROM
I2CEeprom memory(MBED_CONF_APP_I2C_SDA,MBED_CONF_APP_I2C_SCL,MBED_CONF_APP_I2C_EEPROM_ADDR,32,0);

// write to EEPROM
num_written = memory.write(address,Test_String,TEST_STRING_MAX);

// read back from EEPROM
num_read = memory.read(address,(char *)read_string,TEST_STRING_MAX);

// test for equality
TEST_ASSERT_EQUAL_STRING_MESSAGE(Test_String,(char *)read_string,"String read does not match the string written"); // test that strings match
TEST_ASSERT_EQUAL_MESSAGE(num_written,num_read,"Number of bytes written does not match the number of bytes read");
DEBUG_PRINTF("\r\n****\r\n I2C TEST:\r\n Address = `%d`\r\n Num Bytes Written = `%d` \r\n Num Bytes Read = `%d` \r\n String written = `%s` \r\n String read = `%s` \r\n****\r\n",address,num_written,num_read,Test_String,read_string);
osSignalSet(Multi_Thread_ID, 0x1); // signal completion of thread
}


// test SPI API by writing and reading from SD card
void test_SPI()
{
// initialze SD hardware, filesystem, and variables
SDBlockDevice sd(MBED_CONF_APP_SPI_MOSI, MBED_CONF_APP_SPI_MISO, MBED_CONF_APP_SPI_CLK, MBED_CONF_APP_SPI_CS);
FATFileSystem fs("sd", &sd);
sd.init();
fs.mount(&sd);
FILE *File = fopen("/sd/test_sd_w.txt", "w");
TEST_ASSERT_MESSAGE(File != NULL,"SD Card is not present. Please insert an SD Card.");
volatile char read_string[TEST_STRING_MAX] = {0};

// write data to SD card
int error = fprintf(File, Test_String); // write data
TEST_ASSERT_MESSAGE(error > 0,"Writing file to sd card failed"); // error checking
fclose(File); // close file on SD

// read data from SD card
File = fopen("/sd/test_sd_w.txt", "r");
fgets((char *)read_string,TEST_STRING_MAX,File); // read string from the file

// test for equality
TEST_ASSERT_EQUAL_STRING_MESSAGE(Test_String,(char *)read_string,"String read does not match the string written"); // test that strings match
DEBUG_PRINTF("\r\n****\r\n SPI TEST:\r\n String written = `%s` \r\n String read = `%s` \r\n****\r\n",Test_String,read_string);

// close, unmount, and deinitialize
fclose(File); // close file on SD
fs.unmount();
sd.deinit();
osSignalSet(Multi_Thread_ID, 0x2); // signal completion of thread
}


// test I2C and SPI APIs concurrently in multiple threads
void test_multiple_threads()
{
Multi_Thread_ID = Thread::gettid(); // update thread id for this thread
Thread_I2C.start(callback(test_I2C)); // kick off threads
Thread_SPI.start(callback(test_SPI)); // kick off threads
wait(0.1); // allow time for debug print statements to complete.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need this wait? Since it is waiting for threads to set their signal I do not believe you need the wait

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, both threads could complete their work, and the test could exit before the debug print finishes its printing.


// Use this to wait for both signaling events to occur
// Internaly the code is doing something like this:
// if ((signal1 | signal2) & 0x3 == 0x3) then exit, else wait
osSignalWait(0x3, osWaitForever);
}


// test I2C and SPI APIs concurrently in a single thread
void test_single_thread()
{
// *******************************
// Initialize variables and APIs
// *******************************

// I2C test initializations
int address = 0; // starting address to write to in EEPROM
int num_read = 0; // will report number of bytes read
int num_written = 0; // will report number of bytes written
volatile char read_string_i2c[TEST_STRING_MAX] = {0}; // string that will be updated from reading EEPROM
I2CEeprom memory(MBED_CONF_APP_I2C_SDA,MBED_CONF_APP_I2C_SCL,MBED_CONF_APP_I2C_EEPROM_ADDR,32,0);

// SPI test initializations
volatile char read_string_spi[TEST_STRING_MAX] = {0}; // string that will be updated from reading SD card
SDBlockDevice sd(MBED_CONF_APP_SPI_MOSI, MBED_CONF_APP_SPI_MISO, MBED_CONF_APP_SPI_CLK, MBED_CONF_APP_SPI_CS);
FATFileSystem fs("sd", &sd);
sd.init();
fs.mount(&sd);
FILE *File = fopen("/sd/test_sd_w.txt", "w");
TEST_ASSERT_MESSAGE(File != NULL,"SD Card is not present. Please insert an SD Card.");

// ******************************
// Begin concurrent API testing
// ******************************
// write to EEPROM using I2C
num_written = memory.write(address,Test_String,TEST_STRING_MAX);

// write to SD card using SPI
int error = fprintf(File, Test_String); // write data
TEST_ASSERT_MESSAGE(error > 0,"Writing file to sd card failed"); // error checking
fclose(File); // close file on SD

// read back from EEPROM
num_read = memory.read(address,(char *)read_string_i2c,TEST_STRING_MAX);

// read data from SD card
File = fopen("/sd/test_sd_w.txt", "r");
fgets((char *)read_string_spi,TEST_STRING_MAX,File); // read string from the file

// ******************************
// Check results
// ******************************

// test results for I2C
TEST_ASSERT_EQUAL_STRING_MESSAGE(Test_String,(char *)read_string_i2c,"String read does not match the string written"); // test that strings match
TEST_ASSERT_EQUAL_MESSAGE(num_written,num_read,"Number of bytes written does not match the number of bytes read");
DEBUG_PRINTF("\r\n****\r\n I2C TEST:\r\n Address = `%d`\r\n Num Bytes Written = `%d` \r\n Num Bytes Read = `%d` \r\n String written = `%s` \r\n String read = `%s` \r\n****\r\n",address,num_written,num_read,Test_String,read_string_i2c);

// test results for SPI
TEST_ASSERT_EQUAL_STRING_MESSAGE(Test_String,(char *)read_string_spi,"String read does not match the string written"); // test that strings match
DEBUG_PRINTF("\r\n****\r\n SPI TEST:\r\n String written = `%s` \r\n String read = `%s` \r\n****\r\n",Test_String,read_string_spi);
fclose(File); // close file on SD
fs.unmount(); // unmount
sd.deinit(); // deinitialize SD
}


utest::v1::status_t test_setup(const size_t number_of_cases)
{
// Setup Greentea using a reasonable timeout in seconds
GREENTEA_SETUP(40, "default_auto");
return verbose_test_setup_handler(number_of_cases);
}


// Handle test failures, keep testing, dont stop
utest::v1::status_t greentea_failure_handler(const Case *const source, const failure_t reason)
{
greentea_case_failure_abort_handler(source, reason);
return STATUS_CONTINUE;
}


// Test cases
Case cases[] = {
Case("Concurrent testing of I2C and SPI in a single thread",test_single_thread,greentea_failure_handler),
Case("Concurrent testing of I2C and SPI in multiple threads",test_multiple_threads,greentea_failure_handler),
};


Specification specification(test_setup, cases);

// // Entry point into the tests
int main() {
init_string();
return !Harness::run(specification);
}
140 changes: 140 additions & 0 deletions TESTS/concurrent/GPIO/GPIO.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/*
* Copyright (c) 2016 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "mbed.h"
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include "ci_test_config.h"

using namespace utest::v1;

volatile bool Result = false;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need a check to see if AnalogIn is enabled before running this test

// Callback for all InterruptInput functions
void cbfn(void)
{
Result = true;
}


// Template to test DigitalIO, AnalogIn, and InterruptIn pins. Meant to be re-used multiple times
template <PinName digitalOut_pin, PinName digitalIn_pin, PinName analogIn_pin, PinName analogBus_pin1, PinName analogBus_pin2, PinName analogBus_pin3, PinName analogBus_pin4, PinName analogBus_pin5, PinName interruptIn_pin, PinName interruptOut_pin>


void GPIO_Test()
{
// ***********************
// Initialize API pins
// ***********************
DEBUG_PRINTF("Initializing API pins\n");
// Pins for DIO test
DigitalOut d_out(digitalOut_pin);
DigitalIn d_in(digitalIn_pin);

// Pins for AnalogIn test
AnalogIn a_in(analogIn_pin);
BusInOut aBus_outputs(analogBus_pin1,analogBus_pin2,analogBus_pin3,analogBus_pin4,analogBus_pin5);

// Pins for InterruptIn test
InterruptIn int_in(interruptIn_pin);
DigitalOut int_out(interruptOut_pin);

// ***********************
// Begin concurrent API testing
// ***********************
DEBUG_PRINTF("Begining concurrent API testing\n");
aBus_outputs.output();
int analogOut_value= 0;
aBus_outputs = 0;
float prev_analog_value = 0;
for(int iter = 0; iter<5; iter++) {
// DigitalIO test
d_out = 0; // test 0
TEST_ASSERT_MESSAGE(0 == d_in.read(),"Expected value to be 0, read value was not zero");
d_out = 1; // test 1
TEST_ASSERT_MESSAGE(1 == d_in.read(),"Expected value to be 1, read value was not one");

// AnalogIn test
prev_analog_value = a_in.read();
analogOut_value = (analogOut_value << 1) + 1;
aBus_outputs = analogOut_value;
TEST_ASSERT_MESSAGE(a_in.read() > prev_analog_value,"Analog Input did not increment.");

// Rising Edge InterruptIn test
Result = false;
int_out = 0;
int_in.rise(cbfn);
int_out = 1;
wait(0); // dummy wait to get volatile result value
TEST_ASSERT_MESSAGE(Result,"cbfn was not triggered on rising edge of pin");

// Falling Edge InterruptIn test
Result = false;
int_out = 1;
int_in.fall(cbfn);
int_out = 0;
wait(0); // dummy wait to get volatile result value
TEST_ASSERT_MESSAGE(Result,"cbfn was not triggered on falling edge of pin");
}
}


utest::v1::status_t test_setup(const size_t number_of_cases)
{
// Setup Greentea using a reasonable timeout in seconds
GREENTEA_SETUP(30, "default_auto");
return verbose_test_setup_handler(number_of_cases);
}


// Handle test failures, keep testing, dont stop
utest::v1::status_t greentea_failure_handler(const Case *const source, const failure_t reason)
{
greentea_case_failure_abort_handler(source, reason);
return STATUS_CONTINUE;
}


// Test cases
// Runs three different APIs concurrently, DIO, AnalogIn, and InterruptIn
Case cases[] = {
Case("Concurrent testing of DIO(D2,D3), AnalogIn(A0), and InterruptIn(D4,D5)",GPIO_Test<MBED_CONF_APP_DIO_2,MBED_CONF_APP_DIO_3,MBED_CONF_APP_AIN_0,MBED_CONF_APP_AIN_1,MBED_CONF_APP_AIN_2,MBED_CONF_APP_AIN_3,MBED_CONF_APP_AIN_4,MBED_CONF_APP_AIN_5,MBED_CONF_APP_DIO_4,MBED_CONF_APP_DIO_5>,greentea_failure_handler),

Case("Concurrent testing of DIO(D3,D2), AnalogIn(A1), and InterruptIn(D5,D4)",GPIO_Test<MBED_CONF_APP_DIO_3,MBED_CONF_APP_DIO_2, MBED_CONF_APP_AIN_1,MBED_CONF_APP_AIN_2,MBED_CONF_APP_AIN_3,MBED_CONF_APP_AIN_4,MBED_CONF_APP_AIN_5,MBED_CONF_APP_AIN_0,MBED_CONF_APP_DIO_5,MBED_CONF_APP_DIO_4>,greentea_failure_handler),

Case("Concurrent testing of DIO(D4,D5), AnalogIn(A2), and InterruptIn(D6,D7)",GPIO_Test<MBED_CONF_APP_DIO_4,MBED_CONF_APP_DIO_5, MBED_CONF_APP_AIN_2,MBED_CONF_APP_AIN_3,MBED_CONF_APP_AIN_4,MBED_CONF_APP_AIN_5,MBED_CONF_APP_AIN_0,MBED_CONF_APP_AIN_1,MBED_CONF_APP_DIO_6,MBED_CONF_APP_DIO_7>,greentea_failure_handler),

Case("Concurrent testing of DIO(D5,D4), AnalogIn(A3), and InterruptIn(D7,D6)",GPIO_Test<MBED_CONF_APP_DIO_5,MBED_CONF_APP_DIO_4, MBED_CONF_APP_AIN_3,MBED_CONF_APP_AIN_4,MBED_CONF_APP_AIN_5,MBED_CONF_APP_AIN_0,MBED_CONF_APP_AIN_1,MBED_CONF_APP_AIN_2,MBED_CONF_APP_DIO_7,MBED_CONF_APP_DIO_6>,greentea_failure_handler),

Case("Concurrent testing of DIO(D6,D7), AnalogIn(A4), and InterruptIn(D8,D9)",GPIO_Test<MBED_CONF_APP_DIO_6,MBED_CONF_APP_DIO_7, MBED_CONF_APP_AIN_4,MBED_CONF_APP_AIN_5,MBED_CONF_APP_AIN_0,MBED_CONF_APP_AIN_1,MBED_CONF_APP_AIN_2,MBED_CONF_APP_AIN_3,MBED_CONF_APP_DIO_8,MBED_CONF_APP_DIO_9>,greentea_failure_handler),

Case("Concurrent testing of DIO(D7,D6), AnalogIn(A5), and InterruptIn(D9,D8)",GPIO_Test<MBED_CONF_APP_DIO_7,MBED_CONF_APP_DIO_6, MBED_CONF_APP_AIN_5,MBED_CONF_APP_AIN_0,MBED_CONF_APP_AIN_1,MBED_CONF_APP_AIN_2,MBED_CONF_APP_AIN_3,MBED_CONF_APP_AIN_4,MBED_CONF_APP_DIO_9,MBED_CONF_APP_DIO_8>,greentea_failure_handler),

Case("Concurrent testing of DIO(D8,D9), AnalogIn(A5), and InterruptIn(D2,D3)",GPIO_Test<MBED_CONF_APP_DIO_8,MBED_CONF_APP_DIO_9, MBED_CONF_APP_AIN_5,MBED_CONF_APP_AIN_0,MBED_CONF_APP_AIN_1,MBED_CONF_APP_AIN_2,MBED_CONF_APP_AIN_3,MBED_CONF_APP_AIN_4,MBED_CONF_APP_DIO_2,MBED_CONF_APP_DIO_3>,greentea_failure_handler),

Case("Concurrent testing of DIO(D9,D8), AnalogIn(A5), and InterruptIn(D3,D2)",GPIO_Test<MBED_CONF_APP_DIO_9,MBED_CONF_APP_DIO_8, MBED_CONF_APP_AIN_5,MBED_CONF_APP_AIN_0,MBED_CONF_APP_AIN_1,MBED_CONF_APP_AIN_2,MBED_CONF_APP_AIN_3,MBED_CONF_APP_AIN_4,MBED_CONF_APP_DIO_3,MBED_CONF_APP_DIO_2>,greentea_failure_handler),
};


Specification specification(test_setup, cases);


// Entry point into the tests
int main()
{
return !Harness::run(specification);
}
Loading