/////////////////////////////////////////////////////////////////////
//                                                                 //
// Copyright (c) 2019 Acroname Inc. - All Rights Reserved          //
//                                                                 //
// This file is part of the BrainStem release. See the license.txt //
// file included with this package or go to                        //
// https://acroname.com/software/brainstem-development-kit         //
// for full license details.                                       //
/////////////////////////////////////////////////////////////////////
//
// This Example shows creating a signal loopback with the MTMUSBStem. Since this is a
// signal loopback, this example assumes you have a jumper cable connection between Digital pins
// 6 and 4. Please see the product datasheet and the reference material at: http://acroname.com/reference
//    1. Create a MTMUSBStem object and connect.
//    2. Configure the MTMUSBStem to output a square wave via digital pin 6.
//    3. Set the T3 Time for signal entity 2 to 100000000.
//    4. Get and display the T3 Time for signal entity 2.
//    5. Set the T2 Time for signal entity 2 to 50000000.
//    6. Get and display the T2 Time for signal entity 2.
//    7. Enable the signal output on signal entity 2.
//    8. Configure the MTMUSBStem to receive a square wave via digital pin 4.
//    9. Enable the signal input on signal entity 0.
//    10. Get and display the T3 Time for signal entity 0.
//    11. Get and display the T2 Time for signal entity 0.
//    12. Calculate the Duty Cycle with the read T3 and T2 values.
//    13. Disable the signal output on signal entity 2.
//    14. Disable the signal input on signal entity 0.
//    15. Disconnect from the MTMUSBStem object.
///////////////////////////////////////////////////////////////////////

using System;
using System.Threading;
using Acroname.BrainStem2CLI;

namespace BrainStem2CLI_Signal
{
    class Program
    {
        /*
         * Lookup Table for Signal to Digital Mapping
         * The indicies refer to the signal [0-4], while the values
         * held in those indicies refer to the digital pins they
         * are associated with.
         * Note: This Lookup Table is for the MTMUSBStem only.
         * Digital Entity to Signal Entity mapping varies per
         * device. Please refer to the data sheet for the MTM
         * Device you are using to see its unique mapping.
         */
        static int[] signalToDigitalMapping = new int[] { 4, 5, 6, 7, 8 };

        const int T3_TIME = 100000000; // T3 Time. Editable by user
        const int T2_TIME = 50000000; // T2 Time. Editable by user

        // Signal Entity indexs to be used for input and output.
        const int SIGNAL_OUTPUT_IDX = 2;
        const int SIGNAL_INPUT_IDX = 0;

        //Main:
        static void Main(string[] args)
        {
            aErr err = aErr.aErrNone; // aErr variable which will hold the return value of the last command executed
            MTMUSBStem stem = new MTMUSBStem(); // The MTMUSBStem object used to connect to the physical MTMUSBStem
            uint readFromOutputT3Time = 0; // The T3 Time read from the output signal entity (signal entity 2)
            uint readFromOutputT2Time = 0; // The T2 Time read from the output signal entity (signal entity 2)
            uint readFromInputT3Time = 0; // The T3 Time read from the input signal entity (signal entity 0)
            uint readFromInputT2Time = 0; // The T3 Time read from the input signal entity (signal entity 0)
            double dutyCycle = 0.0; // The Duty Cycle calculated from readFromInputT3Time and readFromInputT2Time

            Console.WriteLine("Example: Signal\n\n");

            // Connect to the MTMUSBStem object we created a few lines above
            err = stem.module.discoverAndConnect(m_linkType.USB);
            if (err != aErr.aErrNone)
            {
                Console.WriteLine("Unable to find BrainStem Module: {0}, Error: {1}. Aborting example!\n", stem, (int)err);
                goto FatalError;
            }

            Console.WriteLine("Found and Connected to a {0}\n", stem);

            /*
             * Output
             */

            // Configure the MTMUSBStem to output a square wave via digital pin 6
            err = stem.digital[signalToDigitalMapping[SIGNAL_OUTPUT_IDX]].setConfiguration(6);
            if (err != aErr.aErrNone)
            {
                Console.WriteLine("Error {0} encountered attempting to set the configuration for digital pin 6 on the MTMUSBStem. Aborting example!\n", (int)err);
                goto FatalError;
            }

            // Set the T3 Time for signal entity 2 to 100000000
            err = stem.signal[SIGNAL_OUTPUT_IDX].setT3Time(T3_TIME);
            if (err != aErr.aErrNone)
            {
                Console.WriteLine("Error {0} encountered attempting to set the T3 Time for signal entity 2 on the MTMUSBStem. Aborting example!", (int)err);
                goto FatalError;
            }
            else
            {
                // Get and display the T3 Time from signal entity 2
                err = stem.signal[SIGNAL_OUTPUT_IDX].getT3Time(ref readFromOutputT3Time);
                if (err != aErr.aErrNone)
                    Console.WriteLine("Error {0} encountered attempting to get the T3 Time for signal entity 2 on the MTMUSBStem.", (int)err);
                else if (readFromOutputT3Time == 0)
                {
                    Console.WriteLine("T3 cannot be 0. Aborting example!");
                    goto FatalError;
                }
                else
                    Console.WriteLine("T3 Time from Output Pin: {0}", readFromOutputT3Time);
            }

            // Set the T2 Time for signal entity 2 to 50000000
            err = stem.signal[SIGNAL_OUTPUT_IDX].setT2Time(T2_TIME);
            if (err != aErr.aErrNone)
            {
                Console.WriteLine("Error {0} encountered attempting to set the T2 Time for signal entity 2 on the MTMUSBStem. Aborting example!", (int)err);
                goto FatalError;
            }
            else
            {
                // Get and display the T2 Time for signal entity 2
                err = stem.signal[SIGNAL_OUTPUT_IDX].getT2Time(ref readFromOutputT2Time);
                if (err != aErr.aErrNone)
                    Console.WriteLine("Error {0} encountered attempting to get the T2 Time for signal entity 2 on the MTMUSBStem", (int)err);
                else
                    Console.WriteLine("T2 Time from Output Pin: {0}", readFromOutputT2Time);
            }

            Console.WriteLine("");

            // Enable the signal output on signal entity 2
            err = stem.signal[SIGNAL_OUTPUT_IDX].setEnable(1);
            if (err != aErr.aErrNone)
            {
                Console.WriteLine("Error {0} encountered attempting to set the signal enabled state of signal entity 2 to true on the MTMUSBStem. Aborting example!\n", (int)err);
                goto FatalError;
            }

            /*
             * Input
             */

            // Configure the MTMUSBStem to receive a square wave via digital pin 4
            err = stem.digital[signalToDigitalMapping[SIGNAL_INPUT_IDX]].setConfiguration(7);
            if (err != aErr.aErrNone)
            {
                Console.WriteLine("Error {0} encountered attempting to set the configuration for digital pin 4 on the MTMUSBStem. Aborting example!\n", (int)err);
                goto FatalError;
            }

            // Enable the signal input on signal entity 0
            err = stem.signal[SIGNAL_INPUT_IDX].setEnable(1);
            if (err != aErr.aErrNone)
            {
                Console.WriteLine("Error {0} encountered attempting to set the signal enabled state of signal entity 0 to true on the MTMUSBStem. Aborting example!\n", (int)err);
                goto FatalError;
            }

            /*
             * Sleep for 500ms so the ouput can stabilize
             * and the input can have time to calculate the
             * time high/low
             */
            Thread.Sleep(500);

            // Get and display the T3 Time for signal entity 0
            err = stem.signal[SIGNAL_INPUT_IDX].getT3Time(ref readFromInputT3Time);
            if (err != aErr.aErrNone)
            {
                Console.WriteLine("Error {0} encountered attempting to get the T3 Time for signal entity 0 on the MTMUSBStem. Aborting example!", (int)err);
                goto FatalError;
            }
            else if (readFromInputT3Time == 0)
            {
                Console.WriteLine("T3 Time cannot be 0. Aborting example!");
                goto FatalError;
            }
            else
                Console.WriteLine("T3 Time from Input Pin: {0}", readFromInputT3Time);

            // Get and display the T2 Time for signal entity 0
            err = stem.signal[SIGNAL_INPUT_IDX].getT2Time(ref readFromInputT2Time);
            if (err != aErr.aErrNone)
            {
                Console.WriteLine("Error {0} encountered attempting to get the T2 Time for signal entity 0 on the MTMUSBStem. Aborting example!", (int)err);
                goto FatalError;
            }
            else
                Console.WriteLine("T2 Time from Input Pin: {0}", readFromInputT2Time);

            Console.WriteLine("");

            dutyCycle = ((double)readFromInputT2Time / (double)readFromInputT3Time) * 100.0; // Calculate the Duty Cycle

            Console.WriteLine("Duty Cycle: {0:G}\n", dutyCycle); // Display the Duty Cycle

            // Disable the signal output on signal entity 2
            err = stem.signal[SIGNAL_OUTPUT_IDX].setEnable(0);
            if (err != aErr.aErrNone)
                Console.WriteLine("Error {0} encountered attempting to set the signal enabled state of signal entity 2 to false on the MTMUSBStem\n", (int)err);

            // Disable the signal input on signal entity 0
            err = stem.signal[SIGNAL_INPUT_IDX].setEnable(0);
            if (err != aErr.aErrNone)
                Console.WriteLine("Error {0} encountered attempting to set the signal enabled state of signal entity 0 to false on the MTMUSBStem\n", (int)err);

            stem.module.disconnect(); // Disconnect from the MTMUSBStem

            Console.WriteLine("");

            Console.WriteLine("Finished with Signal Example.");
            Console.WriteLine("--------------------------------------------------------");

            Console.WriteLine("Press enter to exit");
            Console.ReadLine();

            FatalError:
            {
                stem.module.disconnect(); // Disconnect from the MTMUSBStem

                Console.WriteLine("");

                Console.WriteLine("Fatal Error Occurred!");
                Console.WriteLine("Signal Example was aborted.");
                Console.WriteLine("--------------------------------------------------------");

                Console.WriteLine("Press enter to exit");
                Console.ReadLine();
            }
        }
        ///////////////////////////////////////////////////////////////////////
    }
}
