minimalist hardware testing support

Dependents:   MAX5715BOB_Tester MAX11131BOB_Tester MAX5171BOB_Tester MAX11410BOB_Tester ... more

MaximTinyTester.cpp

Committer:
whismanoid
Date:
2020-03-29
Revision:
11:bfa56dab822c
Parent:
10:b11ab5d7ac58
Child:
12:55db0f4a417d

File content as of revision 11:bfa56dab822c:

// /*******************************************************************************
// * Copyright (C) 2019 Maxim Integrated Products, Inc., All Rights Reserved.
// *
// * Permission is hereby granted, free of charge, to any person obtaining a
// * copy of this software and associated documentation files (the "Software"),
// * to deal in the Software without restriction, including without limitation
// * the rights to use, copy, modify, merge, publish, distribute, sublicense,
// * and/or sell copies of the Software, and to permit persons to whom the
// * Software is furnished to do so, subject to the following conditions:
// *
// * The above copyright notice and this permission notice shall be included
// * in all copies or substantial portions of the Software.
// *
// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
// * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// * OTHER DEALINGS IN THE SOFTWARE.
// *
// * Except as contained in this notice, the name of Maxim Integrated
// * Products, Inc. shall not be used except as stated in the Maxim Integrated
// * Products, Inc. Branding Policy.
// *
// * The mere transfer of this software does not imply any licenses
// * of trade secrets, proprietary technology, copyrights, patents,
// * trademarks, maskwork rights, or any other form of intellectual
// * property whatsoever. Maxim Integrated Products, Inc. retains all
// * ownership rights.
// *******************************************************************************
// */
// *********************************************************************
// @file MaximTinyTester.cpp
// *********************************************************************

#include "MaximTinyTester.h"

#ifndef LED_ON
# define LED_ON  0
#endif
#ifndef LED_OFF
# define LED_OFF 1
#endif

MaximTinyTester::MaximTinyTester(CmdLine& AssociatedCmdLine,
    AnalogIn& analogInPin0,
    AnalogIn& analogInPin1,
    AnalogIn& analogInPin2,
    AnalogIn& analogInPin3,
    AnalogIn& analogInPin4,
    AnalogIn& analogInPin5,
    DigitalOut& m_RFailLED,
    DigitalOut& m_GPassLED,
    DigitalOut& m_BBusyLED)
    : associatedCmdLine(AssociatedCmdLine)
    , analogInPin0(analogInPin0)
    , analogInPin1(analogInPin1)
    , analogInPin2(analogInPin2)
    , analogInPin3(analogInPin3)
    , analogInPin4(analogInPin4)
    , analogInPin5(analogInPin5)
    , m_RFailLED(m_RFailLED)
    , m_GPassLED(m_GPassLED)
    , m_BBusyLED(m_BBusyLED)
{
    nPass = 0;
    nFail = 0;
    err_threshold = 0.030; // 30mV
    input_timeout_time_msec = 250;
    settle_time_msec = 250;
    blink_time_msec = 75;
    analogInPin_fullScaleVoltage[0] = 3.300;
    analogInPin_fullScaleVoltage[1] = 3.300;
    analogInPin_fullScaleVoltage[2] = 3.300;
    analogInPin_fullScaleVoltage[3] = 3.300;
    analogInPin_fullScaleVoltage[4] = 3.300;
    analogInPin_fullScaleVoltage[5] = 3.300;
}

/** reset the pass/fail counters.
*
* @post nPass and nFail are reset to 0
*
*/
void MaximTinyTester::clear(void)
{
    nPass = 0;
    nFail = 0;
    // PinName NC means NOT_CONNECTED; DigitalOut::is_connected() returns false
    if (m_RFailLED.is_connected()) {
        m_RFailLED = LED_ON;
    }
    if (m_GPassLED.is_connected()) {
        m_GPassLED = LED_ON;
    }
    if (m_BBusyLED.is_connected()) {
        m_BBusyLED = LED_OFF;
    }
}

/** report that a test has completed with success.
*
* @post nPass is increased by 1
*
*/
void MaximTinyTester::PASS()
{
    ++nPass;
    // m_RFailLED = LED_ON; m_GPassLED = LED_ON; m_BBusyLED = LED_ON;
    // pulse blue LED during test to indicate activity
    if (m_GPassLED.is_connected()) {
        m_GPassLED = LED_OFF;
    }
    if (m_BBusyLED.is_connected()) {
        m_BBusyLED = LED_ON;
    }
    wait_ms(blink_time_msec); // delay
    if (m_GPassLED.is_connected()) {
        m_GPassLED = LED_ON;
    }
    if (m_BBusyLED.is_connected()) {
        m_BBusyLED = LED_OFF;
    }
    wait_ms(blink_time_msec); // delay
    associatedCmdLine.serial().printf("\r\n+PASS ");
}

/** report that a test has completed with failure.
*
* @post nFail is increased by 1
*
*/
void MaximTinyTester::FAIL()
{
    ++nFail;
    // m_RFailLED = LED_ON; m_GPassLED = LED_ON; m_BBusyLED = LED_ON;
    // pulse blue LED during test to indicate activity
    if (m_RFailLED.is_connected()) {
        m_RFailLED = LED_OFF;
    }
    if (m_BBusyLED.is_connected()) {
        m_BBusyLED = LED_ON;
    }
    wait_ms(blink_time_msec); // delay
    if (m_RFailLED.is_connected()) {
        m_RFailLED = LED_ON;
    }
    if (m_BBusyLED.is_connected()) {
        m_BBusyLED = LED_OFF;
    }
    wait_ms(blink_time_msec); // delay
    associatedCmdLine.serial().printf("\r\n-FAIL ");
#if USE_LEDS
    rgb_led.red(); // diagnostic rbg led RED
    //~ rgb_led.green(); // diagnostic rbg led GREEN
    //~ rgb_led.blue(); // diagnostic rbg led BLUE
    //~ rgb_led.white(); // diagnostic rbg led RED+GREEN+BLUE=WHITE
    //~ rgb_led.cyan(); // diagnostic rbg led GREEN+BLUE=CYAN
    //~ rgb_led.magenta(); // diagnostic rbg led RED+BLUE=MAGENTA
    //~ rgb_led.yellow(); // diagnostic rbg led RED+GREEN=YELLOW
    //~ rgb_led.black(); // diagnostic rbg led BLACK
#endif // USE_LEDS
}

/** Print a message to the console during test.
*/
void MaximTinyTester::print(const char* stringLiteralMessage)
{
    associatedCmdLine.serial().printf("\r\n      %s", stringLiteralMessage);
}

/** Report number of pass and number of fail test results
*/
void MaximTinyTester::Report_Summary(void)
{
    associatedCmdLine.serial().printf("\r\nSummary: %d PASS %d FAIL\r\n", nPass, nFail);
    //~ associatedCmdLine.serial().printf(g_SelfTest_nPass);
    //~ associatedCmdLine.serial().printf(" PASS ");
    //~ associatedCmdLine.serial().printf(g_SelfTest_nFail);
    //~ associatedCmdLine.serial().printf(" FAIL\r\n");
    if (nFail == 0) {
        if (m_RFailLED.is_connected()) {
            m_RFailLED = LED_OFF;
        }
        if (m_GPassLED.is_connected()) {
            m_GPassLED = LED_ON;
        }
        if (m_BBusyLED.is_connected()) {
            m_BBusyLED = LED_OFF;
        }
        //~ rgb_led.green();     // diagnostic rbg led GREEN
    }
    else {
        if (m_RFailLED.is_connected()) {
            m_RFailLED = LED_ON;
        }
        if (m_GPassLED.is_connected()) {
            m_GPassLED = LED_OFF;
        }
        if (m_BBusyLED.is_connected()) {
            m_BBusyLED = LED_OFF;
        }
        //~ rgb_led.red(); // diagnostic rbg led RED
    }
}

bool MaximTinyTester::Expect(const char *nameOfTest, int actual_result, int expect_result)
{
    if (actual_result != expect_result)
    {
        FAIL();
        associatedCmdLine.serial().printf("%s", nameOfTest);
        associatedCmdLine.serial().printf(" expect %d", expect_result);
        associatedCmdLine.serial().printf(" but got %d", actual_result);
        return false;
    }
    else
    {
        PASS();
        associatedCmdLine.serial().printf("%s", nameOfTest);
        associatedCmdLine.serial().printf(" expect %d", expect_result);
        return true;
    }
}

bool MaximTinyTester::Expect(const char *nameOfTest, double actual_result, double expect_result)
{
    double err_result = (actual_result - expect_result);
    if (( -err_threshold < err_result) && ( err_result < err_threshold))
    {
        PASS();
        associatedCmdLine.serial().printf("%s", nameOfTest);
        associatedCmdLine.serial().printf(" expect %6.6f", expect_result);
        return true;
    }
    else
    {
        FAIL();
        associatedCmdLine.serial().printf("%s", nameOfTest);
        associatedCmdLine.serial().printf(" expect %6.6f", expect_result);
        associatedCmdLine.serial().printf(" but got %6.6f", actual_result);
        associatedCmdLine.serial().printf(" err=%6.6f", err_result);
        return false;
    }
}

/** Test a software function
*
* @param[in] nameOfFunctionUnderTest is the user-facing name of the function under test
*
* @param[in] functionUnderTest points to the function under test
*
* @param[in] arg_1_voltageV is a test argument given to the function under test
*
* @param[in] expect_result contains the expected result
*
* @post nPass and nFail counters are updated
*
* @return true if success, false if test failed
*
*/
bool MaximTinyTester::FunctionCall_Expect(const char *nameOfFunctionUnderTest, 
    Callback<uint16_t(double)> functionUnderTest,
    double arg_1_voltageV,
    uint16_t expect_result)
{
    uint16_t actual_result = functionUnderTest(arg_1_voltageV);
    if (actual_result != expect_result)
    {
        FAIL();
        associatedCmdLine.serial().printf("%s(%6.4fV)", nameOfFunctionUnderTest, arg_1_voltageV);
        associatedCmdLine.serial().printf(" expect %d", expect_result);
        associatedCmdLine.serial().printf(" but got %d", actual_result);
        return false;
    }
    else
    {
        PASS();
        associatedCmdLine.serial().printf("%s(%6.4fV)", nameOfFunctionUnderTest, arg_1_voltageV);
        associatedCmdLine.serial().printf(" expect %d", expect_result);
        return true;
    }
    //~ associatedCmdLine.serial().printf("\r\n");
}

/** Test a software function
*
* @param[in] nameOfFunctionUnderTest is the user-facing name of the function under test
*
* @param[in] functionUnderTest points to the function under test
*
* @param[in] arg_1_u16 is a test argument given to the function under test
*
* @param[in] expect_result contains the expected result
*
* @pre err_threshold determines how closely the result must match the expected value
*
* @post nPass and nFail counters are updated
*
* @return true if success, false if test failed
*
*/
bool MaximTinyTester::FunctionCall_Expect(const char *nameOfFunctionUnderTest, 
    Callback<double(int)> functionUnderTest,
    int arg_1_u16,
    double expect_result)
{
    double actual_result = functionUnderTest(arg_1_u16);
    double err_result = (actual_result - expect_result);
    if (( -err_threshold < err_result) && ( err_result < err_threshold))
    {
        PASS();
        associatedCmdLine.serial().printf("%s(%d)", nameOfFunctionUnderTest, arg_1_u16);
        associatedCmdLine.serial().printf(" expect %6.6f", expect_result);
        return true;
    }
    else
    {
        FAIL();
        associatedCmdLine.serial().printf("%s(%d)", nameOfFunctionUnderTest, arg_1_u16);
        associatedCmdLine.serial().printf(" expect %6.6f", expect_result);
        associatedCmdLine.serial().printf(" but got %6.6f", actual_result);
        associatedCmdLine.serial().printf(" err=%6.6f", err_result);
        return false;
    }
    //~ associatedCmdLine.serial().printf("\r\n");
}

/** Test a software function
*
* @param[in] nameOfFunctionUnderTest is the user-facing name of the function under test
*
* @param[in] functionUnderTest points to the function under test
*
* @param[in] arg_1_u32 is a test argument given to the function under test
*
* @param[in] expect_result contains the expected result
*
* @pre err_threshold determines how closely the result must match the expected value
*
* @post nPass and nFail counters are updated
*
* @return true if success, false if test failed
*
*/
bool MaximTinyTester::FunctionCall_Expect(const char *nameOfFunctionUnderTest, 
    Callback<double(uint32_t)> functionUnderTest,
    uint32_t arg_1_u32,
    double expect_result)
{
    double actual_result = functionUnderTest(arg_1_u32);
    double err_result = (actual_result - expect_result);
    if (( -err_threshold < err_result) && ( err_result < err_threshold))
    {
        PASS();
        associatedCmdLine.serial().printf("%s(0x%lx)", nameOfFunctionUnderTest, arg_1_u32);
        associatedCmdLine.serial().printf(" expect %6.6f", expect_result);
        return true;
    }
    else
    {
        FAIL();
        associatedCmdLine.serial().printf("%s(0x%lx)", nameOfFunctionUnderTest, arg_1_u32);
        associatedCmdLine.serial().printf(" expect %6.6f", expect_result);
        associatedCmdLine.serial().printf(" but got %6.6f", actual_result);
        associatedCmdLine.serial().printf(" err=%6.6f", err_result);
        return false;
    }
    //~ associatedCmdLine.serial().printf("\r\n");
}

/** Test a software function
*
* @param[in] nameOfFunctionUnderTest is the user-facing name of the function under test
*
* @param[in] functionUnderTest points to the function under test
*
* @param[in] arg_1_d is a test argument given to the function under test
*
* @param[in] expect_result contains the expected result
*
* @pre err_threshold determines how closely the result must match the expected value
*
* @post nPass and nFail counters are updated
*
* @return true if success, false if test failed
*
*/
bool MaximTinyTester::FunctionCall_Expect(const char *nameOfFunctionUnderTest, 
    Callback<double(double)> functionUnderTest,
    double arg_1_d,
    double expect_result)
{
    double actual_result = functionUnderTest(arg_1_d);
    double err_result = (actual_result - expect_result);
    if (( -err_threshold < err_result) && ( err_result < err_threshold))
    {
        PASS();
        associatedCmdLine.serial().printf("%s(%6.6f)", nameOfFunctionUnderTest, arg_1_d);
        associatedCmdLine.serial().printf(" expect %6.6f", expect_result);
        return true;
    }
    else
    {
        FAIL();
        associatedCmdLine.serial().printf("%s(%6.6f)", nameOfFunctionUnderTest, arg_1_d);
        associatedCmdLine.serial().printf(" expect %6.6f", expect_result);
        associatedCmdLine.serial().printf(" but got %6.6f", actual_result);
        associatedCmdLine.serial().printf(" err=%6.6f", err_result);
        return false;
    }
    //~ associatedCmdLine.serial().printf("\r\n");
}

/** Test a software function
*
* @param[in] nameOfFunctionUnderTest is the user-facing name of the function under test
*
* @param[in] functionUnderTest points to the function under test
*
* @param[in] expect_result contains the expected result
*
* @post nPass and nFail counters are updated
*
* @return true if success, false if test failed
*
*/
bool MaximTinyTester::FunctionCall_Expect(const char *nameOfFunctionUnderTest, 
    Callback<uint8_t()> functionUnderTest,
    uint8_t expect_result)
{
    uint8_t actual_result = functionUnderTest();
    if (actual_result != expect_result)
    {
        FAIL();
        associatedCmdLine.serial().printf("%s()", nameOfFunctionUnderTest);
        associatedCmdLine.serial().printf(" expect %d", expect_result);
        associatedCmdLine.serial().printf(" but got %d", actual_result);
        return false;
    }
    else
    {
        PASS();
        associatedCmdLine.serial().printf("%s()", nameOfFunctionUnderTest);
        associatedCmdLine.serial().printf(" expect %d", expect_result);
        return true;
    }
    //~ associatedCmdLine.serial().printf("\r\n");
}

/** Test a software function
*
* @param[in] nameOfFunctionUnderTest is the user-facing name of the function under test
*
* @param[in] functionUnderTest points to the function under test
*
* @param[in] arg_1 is a test argument given to the function under test
*
* @param[in] expect_result contains the expected result
*
* @post nPass and nFail counters are updated
*
* @return true if success, false if test failed
*
*/
bool MaximTinyTester::FunctionCall_Expect(const char *nameOfFunctionUnderTest, 
    Callback<uint8_t(int)> functionUnderTest,
    int arg_1,
    uint8_t expect_result)
{
    uint8_t actual_result = functionUnderTest(arg_1);
    if (actual_result != expect_result)
    {
        FAIL();
        associatedCmdLine.serial().printf("%s(%d)", nameOfFunctionUnderTest, arg_1);
        associatedCmdLine.serial().printf(" expect %d", expect_result);
        associatedCmdLine.serial().printf(" but got %d", actual_result);
        return false;
    }
    else
    {
        PASS();
        associatedCmdLine.serial().printf("%s(%d)", nameOfFunctionUnderTest, arg_1);
        associatedCmdLine.serial().printf(" expect %d", expect_result);
        return true;
    }
    //~ associatedCmdLine.serial().printf("\r\n");
}

/** Test a software function
*
* @param[in] nameOfFunctionUnderTest is the user-facing name of the function under test
*
* @param[in] functionUnderTest points to the function under test
*
* @param[in] arg_1 is a test argument given to the function under test
* @param[in] arg_2 is a test argument given to the function under test
*
* @param[in] expect_result contains the expected result
*
* @post nPass and nFail counters are updated
*
* @return true if success, false if test failed
*
*/
bool MaximTinyTester::FunctionCall_Expect(const char *nameOfFunctionUnderTest, 
    Callback<uint8_t(int, int)> functionUnderTest,
    int arg_1,
    int arg_2,
    uint8_t expect_result)
{
    uint8_t actual_result = functionUnderTest(arg_1, arg_2);
    if (actual_result != expect_result)
    {
        FAIL();
        associatedCmdLine.serial().printf("%s(%d,%d)", nameOfFunctionUnderTest, arg_1, arg_2);
        associatedCmdLine.serial().printf(" expect %d", expect_result);
        associatedCmdLine.serial().printf(" but got %d", actual_result);
        return false;
    }
    else
    {
        PASS();
        associatedCmdLine.serial().printf("%s(%d,%d)", nameOfFunctionUnderTest, arg_1, arg_2);
        associatedCmdLine.serial().printf(" expect %d", expect_result);
        return true;
    }
    //~ associatedCmdLine.serial().printf("\r\n");
}

bool MaximTinyTester::FunctionCall_i_pi_Expect(const char *nameOfFunctionUnderTest, 
    Callback<uint8_t(int, uint32_t*)> functionUnderTest,
    int arg_1,
    uint32_t* arg_2,
    uint8_t expect_result,
    uint32_t expect_buffer)
{
    uint8_t actual_result = functionUnderTest(arg_1, arg_2);
    uint32_t actual_buffer = *arg_2;
    if ((actual_result != expect_result) || (actual_buffer != expect_buffer))
    {
        FAIL();
        associatedCmdLine.serial().printf("%s(%d,buf)", nameOfFunctionUnderTest, arg_1);
        //associatedCmdLine.serial().print(nameOfFunctionUnderTest);
        //associatedCmdLine.serial().print("(");
        //associatedCmdLine.serial().print(arg_1);
        //associatedCmdLine.serial().print(F(",buf)"));
        associatedCmdLine.serial().printf(" expect %d buf=%d", expect_result, expect_buffer);
        //associatedCmdLine.serial().print(F(" expect "));
        //associatedCmdLine.serial().print(expect_result);
        //associatedCmdLine.serial().print(F(" buf="));
        //associatedCmdLine.serial().print(expect_buffer);
        associatedCmdLine.serial().printf(" but got %d buf=%d", actual_result, actual_buffer);
        //associatedCmdLine.serial().print(F(" but got "));
        //associatedCmdLine.serial().print(actual_result);
        //associatedCmdLine.serial().print(F(" buf="));
        //associatedCmdLine.serial().print(actual_buffer);
        return false;
    }
    else
    {
        PASS();
        associatedCmdLine.serial().printf("%s(%d,buf)", nameOfFunctionUnderTest, arg_1);
        //associatedCmdLine.serial().print(nameOfFunctionUnderTest);
        //associatedCmdLine.serial().print("(");
        //associatedCmdLine.serial().print(arg_1);
        //associatedCmdLine.serial().print(F(",buf)"));
        associatedCmdLine.serial().printf(" expect %d buf=%d", expect_result, expect_buffer);
        //associatedCmdLine.serial().print(F(" expect "));
        //associatedCmdLine.serial().print(expect_result);
        //associatedCmdLine.serial().print(F(" buf="));
        //associatedCmdLine.serial().print(expect_buffer);
        return true;
    }
    //~ associatedCmdLine.serial().printf("\r\n");
}

/** Test a software function
*
* @param[in] nameOfFunctionUnderTest is the user-facing name of the function under test
*
* @param[in] functionUnderTest points to the function under test
*
* @param[in] arg_1 is a test argument given to the function under test
* @param[in] arg_2 is a test argument given to the function under test
* @param[in] arg_3 is a test argument given to the function under test
*
* @param[in] expect_result contains the expected result
*
* @post nPass and nFail counters are updated
*
* @return true if success, false if test failed
*
*/
bool MaximTinyTester::FunctionCall_Expect(const char *nameOfFunctionUnderTest, 
    Callback<uint8_t(uint8_t, uint8_t, uint8_t)> functionUnderTest,
    uint8_t arg_1,
    uint8_t arg_2,
    uint8_t arg_3,
    uint8_t expect_result)
{
    uint8_t actual_result = functionUnderTest(arg_1, arg_2, arg_3);
    if (actual_result != expect_result)
    {
        FAIL();
        associatedCmdLine.serial().printf("%s(%d,%d,%d)", nameOfFunctionUnderTest, arg_1, arg_2, arg_3);
        associatedCmdLine.serial().printf(" expect %d", expect_result);
        associatedCmdLine.serial().printf(" but got %d", actual_result);
        return false;
    }
    else
    {
        PASS();
        associatedCmdLine.serial().printf("%s(%d,%d,%d)", nameOfFunctionUnderTest, arg_1, arg_2, arg_3);
        associatedCmdLine.serial().printf(" expect %d", expect_result);
        return true;
    }
    //~ associatedCmdLine.serial().printf("\r\n");
}

/** Test a software function
*
* @param[in] nameOfFunctionUnderTest is the user-facing name of the function under test
*
* @param[in] functionUnderTest points to the function under test
*
* @param[in] arg_1 is a test argument given to the function under test
* @param[in] arg_2 is a test argument given to the function under test
* @param[in] arg_3 is a test argument given to the function under test
* @param[in] arg_4 is a test argument given to the function under test
*
* @param[in] expect_result contains the expected result
*
* @post nPass and nFail counters are updated
*
* @return true if success, false if test failed
*
*/
bool MaximTinyTester::FunctionCall_Expect(const char *nameOfFunctionUnderTest, 
    Callback<uint8_t(uint8_t, uint8_t, uint8_t, uint8_t)> functionUnderTest,
    uint8_t arg_1,
    uint8_t arg_2,
    uint8_t arg_3,
    uint8_t arg_4,
    uint8_t expect_result)
{
    uint8_t actual_result = functionUnderTest(arg_1, arg_2, arg_3, arg_4);
    if (actual_result != expect_result)
    {
        FAIL();
        associatedCmdLine.serial().printf("%s(%d,%d,%d,%d)", nameOfFunctionUnderTest, arg_1, arg_2, arg_3, arg_4);
        associatedCmdLine.serial().printf(" expect %d", expect_result);
        associatedCmdLine.serial().printf(" but got %d", actual_result);
        return false;
    }
    else
    {
        PASS();
        associatedCmdLine.serial().printf("%s(%d,%d,%d,%d)", nameOfFunctionUnderTest, arg_1, arg_2, arg_3, arg_4);
        associatedCmdLine.serial().printf(" expect %d", expect_result);
        return true;
    }
    //~ associatedCmdLine.serial().printf("\r\n");
}

/** Test a software function
*
* @param[in] nameOfFunctionUnderTest is the user-facing name of the function under test
*
* @param[in] functionUnderTest points to the function under test
*
* @param[in] arg_1 is a test argument given to the function under test
* @param[in] arg_2 is a test argument given to the function under test
* @param[in] arg_3 is a test argument given to the function under test
* @param[in] arg_4 is a test argument given to the function under test
* @param[in] arg_5 is a test argument given to the function under test
*
* @param[in] expect_result contains the expected result
*
* @post nPass and nFail counters are updated
*
* @return true if success, false if test failed
*
*/
bool MaximTinyTester::FunctionCall_Expect(const char *nameOfFunctionUnderTest, 
    Callback<uint8_t(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t)> functionUnderTest,
    uint8_t arg_1,
    uint8_t arg_2,
    uint8_t arg_3,
    uint8_t arg_4,
    uint8_t arg_5,
    uint8_t expect_result)
{
    uint8_t actual_result = functionUnderTest(arg_1, arg_2, arg_3, arg_4, arg_5);
    if (actual_result != expect_result)
    {
        FAIL();
        associatedCmdLine.serial().printf("%s(%d,%d,%d,%d,%d)", nameOfFunctionUnderTest, arg_1, arg_2, arg_3, arg_4, arg_5);
        associatedCmdLine.serial().printf(" expect %d", expect_result);
        associatedCmdLine.serial().printf(" but got %d", actual_result);
        return false;
    }
    else
    {
        PASS();
        associatedCmdLine.serial().printf("%s(%d,%d,%d,%d,%d)", nameOfFunctionUnderTest, arg_1, arg_2, arg_3, arg_4, arg_5);
        associatedCmdLine.serial().printf(" expect %d", expect_result);
        return true;
    }
    //~ associatedCmdLine.serial().printf("\r\n");
}

// TODO1 #167 support callback<uint8_t(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t)>
/** Test a software function
*
* @param[in] nameOfFunctionUnderTest is the user-facing name of the function under test
*
* @param[in] functionUnderTest points to the function under test
*
* @param[in] arg_1 is a test argument given to the function under test
* @param[in] arg_2 is a test argument given to the function under test
* @param[in] arg_3 is a test argument given to the function under test
* @param[in] arg_4 is a test argument given to the function under test
* @param[in] arg_5 is a test argument given to the function under test
* @param[in] arg_6 is a test argument given to the function under test
*
* @param[in] expect_result contains the expected result
*
* @post nPass and nFail counters are updated
*
* @return true if success, false if test failed
*
*/
//bool MaximTinyTester::FunctionCall_Expect(const char *nameOfFunctionUnderTest, 
//    Callback<uint8_t(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t)> functionUnderTest,
//    uint8_t arg_1,
//    uint8_t arg_2,
//    uint8_t arg_3,
//    uint8_t arg_4,
//    uint8_t arg_5,
//    uint8_t arg_6,
//    uint8_t expect_result)
//{
//    uint8_t actual_result = functionUnderTest(arg_1, arg_2, arg_3, arg_4, arg_5, arg_6);
//    if (actual_result != expect_result)
//    {
//        FAIL();
//        associatedCmdLine.serial().printf("%s(%d,%d,%d,%d,%d,%d)", nameOfFunctionUnderTest, arg_1, arg_2, arg_3, arg_4, arg_5, arg_6);
//        associatedCmdLine.serial().printf(" expect %d", expect_result);
//        associatedCmdLine.serial().printf(" but got %d", actual_result);
//        return false;
//    }
//    else
//    {
//        PASS();
//        associatedCmdLine.serial().printf("%s(%d,%d,%d,%d,%d,%d)", nameOfFunctionUnderTest, arg_1, arg_2, arg_3, arg_4, arg_5, arg_6);
//        associatedCmdLine.serial().printf(" expect %d", expect_result);
//        return true;
//    }
//    //~ associatedCmdLine.serial().printf("\r\n");
//}

/** Test an analog voltage input to the platform (output from the device under test)
*
* @param[in] expect_result contains the expected voltage
*
* @pre err_threshold determines how closely the result must match the expected value
*
* @post nPass and nFail counters are updated
*
* @return true if success, false if test failed
*
*/
bool MaximTinyTester::AnalogIn0_Read_Expect_voltageV(double expect_result)
{
    float adc_full_scale_voltage = analogInPin_fullScaleVoltage[0];
    // skip if expect_result exceeds ADC full scale
    if (adc_full_scale_voltage < expect_result)
    {
        // print a warning message that we can't perform the measurement
        associatedCmdLine.serial().printf("\r\n..... AIN full scale %1.3fV < expect %6.6f cannot perform measurement",
                                adc_full_scale_voltage, expect_result);
        return true; // ignore, test conditions are invalid; do not call PASS() or FAIL()
    }

    // TODO: tinyTester.Analog_Input_Expect_V replaces SelfTest_AnalogInput_Expect_ch_V
    // Platform board uses simple analog inputs
    float normValue_0_1 = analogInPin0.read();
    double actual_result = normValue_0_1 * adc_full_scale_voltage;
    double err_result = (actual_result - expect_result);
    if (( -err_threshold < err_result) && ( err_result < err_threshold))
    {
        PASS();
        //~ SelfTest_print_VoltageOfCode(cmdLine, value_u12);
        // Platform board uses simple analog inputs
        associatedCmdLine.serial().printf("AIN0 = %7.3f%% = %1.3fV  ",
                                normValue_0_1 * 100.0,
                                normValue_0_1 * adc_full_scale_voltage
                                );
        //
        associatedCmdLine.serial().printf(" expect %6.6f +/- %6.6f", expect_result, err_threshold);
        return true;
    }
    else
    {
        FAIL();
        //~ SelfTest_print_VoltageOfCode(cmdLine, value_u12);
        // Platform board uses simple analog inputs
        associatedCmdLine.serial().printf("AIN0 = %7.3f%% = %1.3fV  ",
                                normValue_0_1 * 100.0,
                                normValue_0_1 * adc_full_scale_voltage
                                );
        //
        associatedCmdLine.serial().printf(" expect %6.6f +/- %6.6f", expect_result, err_threshold);
        associatedCmdLine.serial().printf(" but got %6.6f", actual_result);
        associatedCmdLine.serial().printf(" err=%6.6f", err_result);
    }
    //~ associatedCmdLine.serial().printf("\r\n");
    return false;
}

/** Test an analog voltage input to the platform (output from the device under test)
*
* @param[in] expect_result contains the expected voltage
*
* @pre err_threshold determines how closely the result must match the expected value
*
* @post nPass and nFail counters are updated
*
* @return true if success, false if test failed
*
*/
bool MaximTinyTester::AnalogIn1_Read_Expect_voltageV(double expect_result)
{
    float adc_full_scale_voltage = analogInPin_fullScaleVoltage[1];
    // skip if expect_result exceeds ADC full scale
    if (adc_full_scale_voltage < expect_result)
    {
        // print a warning message that we can't perform the measurement
        associatedCmdLine.serial().printf("\r\n..... AIN full scale %1.3fV < expect %6.6f cannot perform measurement",
                                adc_full_scale_voltage, expect_result);
        return true; // ignore, test conditions are invalid; do not call PASS() or FAIL()
    }

    // TODO: tinyTester.Analog_Input_Expect_V replaces SelfTest_AnalogInput_Expect_ch_V
    // Platform board uses simple analog inputs
    float normValue_0_1 = analogInPin1.read();
    double actual_result = normValue_0_1 * adc_full_scale_voltage;
    double err_result = (actual_result - expect_result);
    if (( -err_threshold < err_result) && ( err_result < err_threshold))
    {
        PASS();
        //~ SelfTest_print_VoltageOfCode(cmdLine, value_u12);
        // Platform board uses simple analog inputs
        associatedCmdLine.serial().printf("AIN1 = %7.3f%% = %1.3fV  ",
                                normValue_0_1 * 100.0,
                                normValue_0_1 * adc_full_scale_voltage
                                );
        //
        associatedCmdLine.serial().printf(" expect %6.6f +/- %6.6f", expect_result, err_threshold);
        return true;
    }
    else
    {
        FAIL();
        //~ SelfTest_print_VoltageOfCode(cmdLine, value_u12);
        // Platform board uses simple analog inputs
        associatedCmdLine.serial().printf("AIN1 = %7.3f%% = %1.3fV  ",
                                normValue_0_1 * 100.0,
                                normValue_0_1 * adc_full_scale_voltage
                                );
        //
        associatedCmdLine.serial().printf(" expect %6.6f +/- %6.6f", expect_result, err_threshold);
        associatedCmdLine.serial().printf(" but got %6.6f", actual_result);
        associatedCmdLine.serial().printf(" err=%6.6f", err_result);
    }
    //~ associatedCmdLine.serial().printf("\r\n");
    return false;
}

/** Test an analog voltage input to the platform (output from the device under test)
*
* @param[in] expect_result contains the expected voltage
*
* @pre err_threshold determines how closely the result must match the expected value
*
* @post nPass and nFail counters are updated
*
* @return true if success, false if test failed
*
*/
bool MaximTinyTester::AnalogIn2_Read_Expect_voltageV(double expect_result)
{
    float adc_full_scale_voltage = analogInPin_fullScaleVoltage[2];
    // skip if expect_result exceeds ADC full scale
    if (adc_full_scale_voltage < expect_result)
    {
        // print a warning message that we can't perform the measurement
        associatedCmdLine.serial().printf("\r\n..... AIN full scale %1.3fV < expect %6.6f cannot perform measurement",
                                adc_full_scale_voltage, expect_result);
        return true; // ignore, test conditions are invalid; do not call PASS() or FAIL()
    }

    // TODO: tinyTester.Analog_Input_Expect_V replaces SelfTest_AnalogInput_Expect_ch_V
    // Platform board uses simple analog inputs
    float normValue_0_1 = analogInPin2.read();
    double actual_result = normValue_0_1 * adc_full_scale_voltage;
    double err_result = (actual_result - expect_result);
    if (( -err_threshold < err_result) && ( err_result < err_threshold))
    {
        PASS();
        //~ SelfTest_print_VoltageOfCode(cmdLine, value_u12);
        // Platform board uses simple analog inputs
        associatedCmdLine.serial().printf("AIN2 = %7.3f%% = %1.3fV  ",
                                normValue_0_1 * 100.0,
                                normValue_0_1 * adc_full_scale_voltage
                                );
        //
        associatedCmdLine.serial().printf(" expect %6.6f +/- %6.6f", expect_result, err_threshold);
        return true;
    }
    else
    {
        FAIL();
        //~ SelfTest_print_VoltageOfCode(cmdLine, value_u12);
        // Platform board uses simple analog inputs
        associatedCmdLine.serial().printf("AIN2 = %7.3f%% = %1.3fV  ",
                                normValue_0_1 * 100.0,
                                normValue_0_1 * adc_full_scale_voltage
                                );
        //
        associatedCmdLine.serial().printf(" expect %6.6f +/- %6.6f", expect_result, err_threshold);
        associatedCmdLine.serial().printf(" but got %6.6f", actual_result);
        associatedCmdLine.serial().printf(" err=%6.6f", err_result);
    }
    //~ associatedCmdLine.serial().printf("\r\n");
    return false;
}

/** Test an analog voltage input to the platform (output from the device under test)
*
* @param[in] expect_result contains the expected voltage
*
* @pre err_threshold determines how closely the result must match the expected value
*
* @post nPass and nFail counters are updated
*
* @return true if success, false if test failed
*
*/
bool MaximTinyTester::AnalogIn3_Read_Expect_voltageV(double expect_result)
{
    float adc_full_scale_voltage = analogInPin_fullScaleVoltage[3];
    // skip if expect_result exceeds ADC full scale
    if (adc_full_scale_voltage < expect_result)
    {
        // print a warning message that we can't perform the measurement
        associatedCmdLine.serial().printf("\r\n..... AIN full scale %1.3fV < expect %6.6f cannot perform measurement",
                                adc_full_scale_voltage, expect_result);
        return true; // ignore, test conditions are invalid; do not call PASS() or FAIL()
    }

    // TODO: tinyTester.Analog_Input_Expect_V replaces SelfTest_AnalogInput_Expect_ch_V
    // Platform board uses simple analog inputs
    float normValue_0_1 = analogInPin3.read();
    double actual_result = normValue_0_1 * adc_full_scale_voltage;
    double err_result = (actual_result - expect_result);
    if (( -err_threshold < err_result) && ( err_result < err_threshold))
    {
        PASS();
        //~ SelfTest_print_VoltageOfCode(cmdLine, value_u12);
        // Platform board uses simple analog inputs
        associatedCmdLine.serial().printf("AIN3 = %7.3f%% = %1.3fV  ",
                                normValue_0_1 * 100.0,
                                normValue_0_1 * adc_full_scale_voltage
                                );
        //
        associatedCmdLine.serial().printf(" expect %6.6f +/- %6.6f", expect_result, err_threshold);
        return true;
    }
    else
    {
        FAIL();
        //~ SelfTest_print_VoltageOfCode(cmdLine, value_u12);
        // Platform board uses simple analog inputs
        associatedCmdLine.serial().printf("AIN3 = %7.3f%% = %1.3fV  ",
                                normValue_0_1 * 100.0,
                                normValue_0_1 * adc_full_scale_voltage
                                );
        //
        associatedCmdLine.serial().printf(" expect %6.6f +/- %6.6f", expect_result, err_threshold);
        associatedCmdLine.serial().printf(" but got %6.6f", actual_result);
        associatedCmdLine.serial().printf(" err=%6.6f", err_result);
    }
    //~ associatedCmdLine.serial().printf("\r\n");
    return false;
}

/** Test an analog voltage input to the platform (output from the device under test)
*
* @param[in] expect_result contains the expected voltage
*
* @pre err_threshold determines how closely the result must match the expected value
*
* @post nPass and nFail counters are updated
*
* @return true if success, false if test failed
*
*/
bool MaximTinyTester::AnalogIn4_Read_Expect_voltageV(double expect_result)
{
    float adc_full_scale_voltage = analogInPin_fullScaleVoltage[4];
    // skip if expect_result exceeds ADC full scale
    if (adc_full_scale_voltage < expect_result)
    {
        // print a warning message that we can't perform the measurement
        associatedCmdLine.serial().printf("\r\n..... AIN full scale %1.3fV < expect %6.6f cannot perform measurement",
                                adc_full_scale_voltage, expect_result);
        return true; // ignore, test conditions are invalid; do not call PASS() or FAIL()
    }

    // TODO: tinyTester.Analog_Input_Expect_V replaces SelfTest_AnalogInput_Expect_ch_V
    // Platform board uses simple analog inputs
    float normValue_0_1 = analogInPin4.read();
    double actual_result = normValue_0_1 * adc_full_scale_voltage;
    double err_result = (actual_result - expect_result);
    if (( -err_threshold < err_result) && ( err_result < err_threshold))
    {
        PASS();
        //~ SelfTest_print_VoltageOfCode(cmdLine, value_u12);
        // Platform board uses simple analog inputs
        associatedCmdLine.serial().printf("AIN4 = %7.3f%% = %1.3fV  ",
                                normValue_0_1 * 100.0,
                                normValue_0_1 * adc_full_scale_voltage
                                );
        //
        associatedCmdLine.serial().printf(" expect %6.6f +/- %6.6f", expect_result, err_threshold);
        return true;
    }
    else
    {
        FAIL();
        //~ SelfTest_print_VoltageOfCode(cmdLine, value_u12);
        // Platform board uses simple analog inputs
        associatedCmdLine.serial().printf("AIN4 = %7.3f%% = %1.3fV  ",
                                normValue_0_1 * 100.0,
                                normValue_0_1 * adc_full_scale_voltage
                                );
        //
        associatedCmdLine.serial().printf(" expect %6.6f +/- %6.6f", expect_result, err_threshold);
        associatedCmdLine.serial().printf(" but got %6.6f", actual_result);
        associatedCmdLine.serial().printf(" err=%6.6f", err_result);
    }
    //~ associatedCmdLine.serial().printf("\r\n");
    return false;
}

/** Test an analog voltage input to the platform (output from the device under test)
*
* @param[in] expect_result contains the expected voltage
*
* @pre err_threshold determines how closely the result must match the expected value
*
* @post nPass and nFail counters are updated
*
* @return true if success, false if test failed
*
*/
bool MaximTinyTester::AnalogIn5_Read_Expect_voltageV(double expect_result)
{
    float adc_full_scale_voltage = analogInPin_fullScaleVoltage[5];
    // skip if expect_result exceeds ADC full scale
    if (adc_full_scale_voltage < expect_result)
    {
        // print a warning message that we can't perform the measurement
        associatedCmdLine.serial().printf("\r\n..... AIN full scale %1.3fV < expect %6.6f cannot perform measurement",
                                adc_full_scale_voltage, expect_result);
        return true; // ignore, test conditions are invalid; do not call PASS() or FAIL()
    }

    // TODO: tinyTester.Analog_Input_Expect_V replaces SelfTest_AnalogInput_Expect_ch_V
    // Platform board uses simple analog inputs
    float normValue_0_1 = analogInPin5.read();
    double actual_result = normValue_0_1 * adc_full_scale_voltage;
    double err_result = (actual_result - expect_result);
    if (( -err_threshold < err_result) && ( err_result < err_threshold))
    {
        PASS();
        //~ SelfTest_print_VoltageOfCode(cmdLine, value_u12);
        // Platform board uses simple analog inputs
        associatedCmdLine.serial().printf("AIN5 = %7.3f%% = %1.3fV  ",
                                normValue_0_1 * 100.0,
                                normValue_0_1 * adc_full_scale_voltage
                                );
        //
        associatedCmdLine.serial().printf(" expect %6.6f +/- %6.6f", expect_result, err_threshold);
        return true;
    }
    else
    {
        FAIL();
        //~ SelfTest_print_VoltageOfCode(cmdLine, value_u12);
        // Platform board uses simple analog inputs
        associatedCmdLine.serial().printf("AIN5 = %7.3f%% = %1.3fV  ",
                                normValue_0_1 * 100.0,
                                normValue_0_1 * adc_full_scale_voltage
                                );
        //
        associatedCmdLine.serial().printf(" expect %6.6f +/- %6.6f", expect_result, err_threshold);
        associatedCmdLine.serial().printf(" but got %6.6f", actual_result);
        associatedCmdLine.serial().printf(" err=%6.6f", err_result);
    }
    //~ associatedCmdLine.serial().printf("\r\n");
    return false;
}

bool MaximTinyTester::AnalogIn_Read_Expect_voltageV(AnalogIn& analogInPin, double expect_result)
{
    float adc_full_scale_voltage = analogInPin_fullScaleVoltage[0];
    // skip if expect_result exceeds ADC full scale
    if (adc_full_scale_voltage < expect_result)
    {
        // print a warning message that we can't perform the measurement
        associatedCmdLine.serial().printf("\r\n..... AIN full scale %1.3fV < expect %6.6f cannot perform measurement",
                                adc_full_scale_voltage, expect_result);
        return true; // ignore, test conditions are invalid; do not call PASS() or FAIL()
    }

    // TODO: tinyTester.Analog_Input_Expect_V replaces SelfTest_AnalogInput_Expect_ch_V
    // Platform board uses simple analog inputs
    float normValue_0_1 = analogInPin.read();
    double actual_result = normValue_0_1 * adc_full_scale_voltage;
    double err_result = (actual_result - expect_result);
    if (( -err_threshold < err_result) && ( err_result < err_threshold))
    {
        PASS();
        //~ SelfTest_print_VoltageOfCode(cmdLine, value_u12);
        // Platform board uses simple analog inputs
        associatedCmdLine.serial().printf("AIN0 = %7.3f%% = %1.3fV  ",
                                normValue_0_1 * 100.0,
                                normValue_0_1 * adc_full_scale_voltage
                                );
        //
        associatedCmdLine.serial().printf(" expect %6.6f +/- %6.6f", expect_result, err_threshold);
        return true;
    }
    else
    {
        FAIL();
        //~ SelfTest_print_VoltageOfCode(cmdLine, value_u12);
        // Platform board uses simple analog inputs
        associatedCmdLine.serial().printf("AIN0 = %7.3f%% = %1.3fV  ",
                                normValue_0_1 * 100.0,
                                normValue_0_1 * adc_full_scale_voltage
                                );
        //
        associatedCmdLine.serial().printf(" expect %6.6f +/- %6.6f", expect_result, err_threshold);
        associatedCmdLine.serial().printf(" but got %6.6f", actual_result);
        associatedCmdLine.serial().printf(" err=%6.6f", err_result);
    }
    //~ associatedCmdLine.serial().printf("\r\n");
    return false;
}

bool MaximTinyTester::DigitalIn_Read_Expect_WarnOnly(DigitalIn& digitalInPin, const char* pinName, int expect_result, const char *expect_description)
{
    int actual_UPO_value = -1;
    for (int retry_count = 0; retry_count < 10; retry_count++) {
        actual_UPO_value = digitalInPin.read(); // g_MAX5171_device.UPOinputValue();
        if (actual_UPO_value == expect_result) {
            PASS();
            associatedCmdLine.serial().printf("%s signal=%d %s", pinName, expect_result, expect_description);
            return true;
        }
        // UPO condition not met, retry for a while until give up
        wait_ms(input_timeout_time_msec / 10); // delay
    }
    associatedCmdLine.serial().printf("\r\n!WARN "); // SelfTest_FAIL(cmdLine);
    associatedCmdLine.serial().printf("expected %s signal=%d %s", pinName, expect_result, expect_description);
    associatedCmdLine.serial().printf(", but got actual %s=%d", pinName, actual_UPO_value);
    associatedCmdLine.serial().printf(", missing %s connections?", pinName);
    return false;
}

void MaximTinyTester::Wait_Output_Settling()
{
    wait_ms(settle_time_msec); // delay
}


// End of file