Kenneth Dunlop / Mbed 2 deprecated Ken_CAN_test

Dependencies:   mbed

Ken_CAN_test.cpp

Committer:
kendunlop
Date:
2022-07-11
Revision:
13:e3a4abc461f4
Parent:
12:e950feba910d

File content as of revision 13:e3a4abc461f4:

//This program was created by Ken 8th June 2022 to test the CAN output of a CAN Gateway.
#define kMajorVersion 0 //Defines a major and minor version to be shown later in the program.
#define kMinorVersion 5

#include "mbed.h" //Including mbed libraries. This should be all it needs to use the Mbed and CAN.
#include <string> //This is needed to make text strings work
#include <stdio.h>
#include <ctype.h> //For 'is digit' condition
#include <sstream> //This is used to convert an integer to hex
#include <time.h> //To measure how long a process took? Includes clock_t and CLOCKS_PER_SEC

RawSerial pc(USBTX, USBRX); // USB UART Terminal, tx, rx. Is needed for 'pc.printf' functions to work.

// NOTE: Original pins for CAN Bus 1 are 9 and 10.
CAN CanBus(p9, p10); //CANBus to use pins 9 and 10. This defines CanBus so other 'CanBus' lines will work.
CAN CanBus2(p30, p29); //CANBus2 for recieving to use pins 30 and 29 (in that order!).
CANMessage messageIn;

//Define a CAN message to send
CANMessage messageOut1;

//Set messageOutText to a default message so it's defined.
string messageOutText = "";
string messageOutTextWithSpaces = "";
string buttonPressMessageOutText = "";
string part = "";
int partincrement = 0;
__int64 incrementer = 0;
int CANCount = 0;

int spamon = 0;
int idspamon = 0;
int idscheckedcount = 0;
int spamcount = 0;
int totalspamsever = 0;
int spamstarttime = 0;
int spamendtime = 0;
int spamsecondstotal = 0;
int spamspersecond = 0;
int messagesinpersecond = 0;

int vlistincrementer = 0;
int idlistincrementer = 0;
string spampreamble = "333";
int expected1 = 0;
int expected2 = 0;
unsigned char expected3 = 0;
unsigned char expected4 = 0;
unsigned char expected5 = 0;
unsigned char expected6 = 0;
unsigned char expected7 = 0;
unsigned char expected8 = 0;
unsigned char expected9 = 0;
unsigned char expected10 = 0;
int expectationwasfulfilled = -1;
int expectationresolved = 1;
int expectationtimer = 0;
int shouldntcomein = 0;
int goodnoreplies = 0;
int goodnoreplystreak = 0;
int goodnoreplystreakstartid = 0;
int CANmatchstreak = 0;
int CANmatchstreakstartID = 0;
int unexpectedCANfails = 0;
int unexpectedCANstreak = 0;
int unexpectedCANstreakstartid = 0;
int failsthistest = 0;
int failsstreak = 0;
int failsstreakstart = 0;
int reportfailsindividually = 1;
int noreplyfailsthistest = 0;
int noreplystreak = 0;
int noreplystreakstartid = 0;

int mismatchfailsthistest = 0;
int matchesthistest = 0;
int addnewlinetonextmessage = 0;
int checklaterbytes = 1;
int aspamisgoing = 0;
int CANpassthrough = 1;
int speedspamison = 0;
int messagesincount = 0;
int messageinisneeded = 0;

int idwasfound = 0;
int columnidwasfound = 0;

char c = NULL;

int mbedCANbusspeed = 500 * 1000;
int CANGatewayCANbusspeed = 500 * 1000;
int listen = 1;
int testwasaborted = 0;

int customentry = 0;
int normalkeypresses = 1;
int tablesmode = 0;
string customentrystring = "";
int hextotal = 0;

int numberkeypressed = -1;

//Array of IDs to translate can be overwritten with the 'copyarray'.
//It's arranged in columns of IDs that are translated to the ID in the next column.
//NOTE: Array must be a large enough size to contain all ID translations.
int idsarray[2][8][10] = {};
//int copyarray[2][8][10] = {};
int arrayx = 2;
int arrayy = 8;
int arrayz = 10;
int x = 0;
int y = 0;
int z = 0;
int totalarraysize = 0;

//A function to easily get the total of seconds a spam has taken
int getspamsecondstotal(void)
    {
    //pc.printf("\r\nHere I'll get the spam seconds total!\r\n");
    //pc.printf("Spam start/end time was %d / %d.\r\n", spamstarttime, spamendtime);
    int spamtickstotal = (spamendtime - spamstarttime);
    //pc.printf("Spam ticks total is %d.\r\n", spamtickstotal);
    //pc.printf("CLOCKS_PER_SEC are %d.\r\n", CLOCKS_PER_SEC);
    //pc.printf("Spamcount this test is %d.\r\n", spamcount);
    spamsecondstotal = ((spamendtime - spamstarttime) / CLOCKS_PER_SEC);
    //pc.printf("Spam seconds total is %d.\r\n", spamsecondstotal);
    spamspersecond = (10000 * spamcount);
    messagesinpersecond = (10000 * messagesincount);
    //pc.printf("Spams biggened x 10,000 is %d.\r\n", spamspersecond);
    spamspersecond = (spamspersecond / spamtickstotal);
    messagesinpersecond = (messagesinpersecond / spamtickstotal);
    //pc.printf("Spams per tick, still biggened, is %d.\r\n", spamspersecond);
    spamspersecond = (spamspersecond * CLOCKS_PER_SEC);
    messagesinpersecond = (messagesinpersecond * CLOCKS_PER_SEC);
    //pc.printf("Spams per second, still biggened, given %d ticks per second, is %d.\r\n", CLOCKS_PER_SEC, spamspersecond);
    spamspersecond = (spamspersecond / 10000);
    messagesinpersecond = (messagesinpersecond / 10000);
    //pc.printf("Spams per second, un-biggened, is %d.\r\n", spamspersecond);
    //pc.printf("\r\nSent %d messages for %d ticks (%d seconds) at %d ticks per second. Messages per second is %d.\r\n", spamcount, spamtickstotal, spamsecondstotal, CLOCKS_PER_SEC, spamspersecond); //Old version of the message
    if (speedspamison == 0)
        {
        if (aspamisgoing == 1)
            {
            pc.printf("\n");
            }
        pc.printf("\rSent %d messages over %d seconds. Messages per second is %d.\r\n", spamcount, spamsecondstotal, spamspersecond);
        }
    return(spamsecondstotal, spamspersecond);
    }

//A function to get table cells
void dealwithtable(int copyarray)
    {
    for (int arrayprogress = 0; arrayprogress < totalarraysize; arrayprogress++)
        {
        x++;
        if (x >= arrayx)
            {
            x = 0;
            y++;
            }
        if (y >= arrayy)
            {
            y = 0;
            z++;
            }
        //int cellcontents = copyarray[x][y][z];
        //pc.printf("Array progress is %d. Examining %d,%d,%d. It says '%d'.\r\n", arrayprogress, x, y, z, cellcontents);
        }
    }

//Structure for CAN conversion pair, an ID and ID-plus-message, expressed in strings
struct CANpair {
                string IDfrom;
                string IDmessageto;
               };

struct CANpair CANpairslist[32]; //This defines a list of CANpair string pairs, each with 'IDfrom' and 'IDmessageto'.

//Structure for CAN conversion table
struct CANconversion {
        int IDfrom;
        int IDto;
        int length;
        int Data [8];
        };

struct CANconversion CANconversionlist[32]; //This defines a list of CANconversion structures, each with its own IDfrom, IDto, length, etc. (E.g.: 'CANconversionlist[0].IDfrom')
int CANconversionlistheight = 32;

//A function to reset the CAN pairs list so it can be re-written into
void resetCANpairslist()
    {
    CANconversionlistheight = 0;
    for (int i = 0; i < 32; i++)
        {
        CANpairslist[i].IDfrom = "";
        CANpairslist[i].IDmessageto = "";
        //pc.printf("Emptying CANpairslist row %d.\r\n", i);
        }
    }

//A function to deal with each CAN message part (e.g.: 301, 8, 01, 02...)
void dealwithpart(void)
{
    hextotal = 0;
    partincrement = partincrement + 1;
    //pc.printf("Dealing with part %d. (%s)\r\n", partincrement, part);
    //int partincrementb = 0;
    int textlength = part.length();
    //int characterinc = 0;
    //pc.printf("That's %d characters long.\r\n", textlength);
    for (int i = 0; i < part.size(); i++)
    {
        //pc.printf("Examining character %d/%d.\r\n", (i+1), textlength);
        char individualcharacter = part.at(i);
        //pc.printf("That's '%c'.\r\n", individualcharacter);
        int numberized = 0;
        if(isdigit(individualcharacter))
            {
            //pc.printf("That character is a digit.\r\n");
            numberized = individualcharacter - '0';
            //pc.printf("Numberized that's '%d'.\r\n", numberized);
            }
        else
            {
            //pc.printf("That character is NOT a digit.\r\n");
            int asciivalue = toupper(individualcharacter);
            //pc.printf("Ascii value is %d.\r\n", asciivalue);
            numberized = asciivalue - 55;
            //pc.printf("Hex value is %d.\r\n", numberized);
            }
        //pc.printf("Eventual numberization is %d.\r\n", numberized);
        //pc.printf("Hex total is now %d.\r\n", hextotal);
        int powertoraise = part.size() - (i+1);
        //pc.printf("Must multiply by 16 to the power of %d.\r\n", powertoraise);
        int amounttoadd = numberized;
        //pc.printf("powertoraise is '%d'.\r\n", powertoraise);
        if (powertoraise == 1)
            {
            amounttoadd = numberized * 16;
            //pc.printf("Multiplying by 16.\r\n");
            //pc.printf("powertoraise is '%d'.\r\n", powertoraise);
            }
        if (powertoraise == 2)
            {
            amounttoadd = numberized * 256;
            //pc.printf("Multiplying by 256.\r\n");
            }
        //pc.printf("Amount to add is therefore %d.\r\n", amounttoadd);
        hextotal = hextotal + amounttoadd;
        //pc.printf("hextotal so far for this part is therefore %d.\r\n", hextotal);
    }
    //pc.printf("hextotal for whole part is therefore %d.\r\n", hextotal);
    //pc.printf("Need to convert that into true hex.\r\n");
    std::stringstream sstream;
    sstream << std::hex << hextotal;
    //pc.printf("StringSteam says '%s'.\r\n", sstream.str());
    if (partincrement == 1)
        {
        if (hextotal > 0xFFF)
            {
            hextotal = 0xFFF;
            }
        messageOut1.id = hextotal;
        expected1 = hextotal;
        if (customentry == 1)
            {
            idlistincrementer = hextotal;
            }
        //For IDs, check if the ID is represented in the idsarray.
        shouldntcomein = 0;
        if (mbedCANbusspeed != CANGatewayCANbusspeed)
            {
            shouldntcomein = 1;
            }
        idwasfound = 0;
        if (CANpassthrough == 0)
            {
            for(int i = 0; i <=CANconversionlistheight-1; i++)
                {
                if (CANconversionlist[i].IDfrom == expected1)
                    {
                    //pc.printf("ID was found in the array at %d.\r\n", i);
                    idwasfound = 1;
                    //pc.printf("IDwasfound is now '%d'.\r\n", idwasfound);
                    columnidwasfound = i;
                    int originalexpectedvalue = expected1;
                    //Get string of hex code for original expected value (ID code found in array)
                    std::stringstream sstream;
                    sstream << std::hex << originalexpectedvalue;
                    string tempstring = sstream.str();
                    //Get string of hex code for value to adjust to
                    std::stringstream sstream2;
                    sstream2 << std::hex << expected1;
                    string tempstring2 = sstream2.str();
                    //pc.printf("\r\nFound message ID %s at 0,%d in idsarray! Will adjust expected value to %s.\r\n", tempstring, i, tempstring2);
                    }
                }
            if (idwasfound == 0 and CANpassthrough == 0)
                {
                //pc.printf("CANpassthrough is %d.\r\n", CANpassthrough);
                shouldntcomein = 1;
                //pc.printf("ID of %d was never found, expecting it NOT to come in.\r\n", expected1);
                }
            if (shouldntcomein == 0 and unexpectedCANstreak > 0) //If data is expected to come in, this ends any unexpected-CAN streak.
                {
                if (aspamisgoing == 1) //Add a new line if it's in spam mode here to report new non-unexpected-CAN-streak stuff.
                    {
                    //pc.printf("\r\n(FrombreakingunexpectedCANstreak 2)\n");
                    pc.printf("\r\n\n");
                    }
                unexpectedCANstreak = 0;
                unexpectedCANstreakstartid = 0;
                }
            }
        }
    if (partincrement == 2)
        {
        messageOut1.len = hextotal;
        expected2 = hextotal;
        }
    if (partincrement >= 3)
        {
        messageOut1.data[partincrement-3] = hextotal;
        }
    if (partincrement == 3)
        {
        expected3 = hextotal;
        }
    if (partincrement == 4)
        {
        expected4 = hextotal;
        }
    if (partincrement == 5)
        {
        expected5 = hextotal;
        }
    if (partincrement == 6)
        {
        expected6 = hextotal;
        }
    if (partincrement == 7)
        {
        expected7 = hextotal;
        }    
    if (partincrement == 8)
        {
        expected8 = hextotal;
        }
    if (partincrement == 9)
        {
        expected9 = hextotal;
        }
    if (partincrement == 10)
        {
        expected10 = hextotal;
        }
    //pc.printf("IDwasfound says '%d'.\r\n", idwasfound);
    if (idwasfound == 1 and partincrement == 10)//If the ID was found in the table earlier, use it as the basis for the expected values instead.
        {
        //pc.printf("ID was found in table earlier, setting expectations\r\n");
        int i = columnidwasfound;
        expected1  = CANconversionlist[i].IDto;
        expected2  = CANconversionlist[i].length;
        expected3  = CANconversionlist[i].Data[0];
        expected4  = CANconversionlist[i].Data[1];
        expected5  = CANconversionlist[i].Data[2];
        expected6  = CANconversionlist[i].Data[3];
        expected7  = CANconversionlist[i].Data[4];
        expected8  = CANconversionlist[i].Data[5];
        expected9  = CANconversionlist[i].Data[6];
        expected10 = CANconversionlist[i].Data[7];
        }
    //pc.printf("Part %d complete.\r\n", partincrement);
    //pc.printf("--------------------------------------\r\n");
}

//A function to go through each row in the string CAN pairs list and turn them into data for the CAN conversion list.
void gothroughCANpairslist(void)
    {
    for (int i = 0; i < 30; i++)
        {
        string tempstringA = CANpairslist[i].IDfrom;
        string tempstringB = CANpairslist[i].IDmessageto;
        //pc.printf("Strings found are '%s' and '%s'.\r\n", tempstringA, tempstringB);
        //pc.printf("Will try to get an ID from out of '%s'.\r\n", tempstringA);
        if (tempstringA != "" and tempstringB != "")//Only get a number from the part if tempstring A and B have something in them.
            {
            CANconversionlistheight = i+1;
            partincrement = 0;
            part = tempstringA;
            dealwithpart();
            //pc.printf("Hextotal obtained is %d.\r\n", hextotal);
            //pc.printf("partincrement is now %d.\r\n", partincrement);
            CANconversionlist[i].IDfrom = hextotal;
            partincrement = 0;
            part = tempstringB.substr(0,3);
            dealwithpart();
            //pc.printf("Hextotal obtained is %d.\r\n", hextotal);
            CANconversionlist[i].IDto = hextotal;
            part = tempstringB.substr(4,1);
            dealwithpart();
            //pc.printf("Hextotal obtained is %d.\r\n", hextotal);
            CANconversionlist[i].length = hextotal;
            part = tempstringB.substr(6,2);
            dealwithpart();
            //pc.printf("Hextotal obtained is %d.\r\n", hextotal);
            CANconversionlist[i].Data [0] = hextotal;
            part = tempstringB.substr(9,2);
            dealwithpart();
            //pc.printf("Hextotal obtained is %d.\r\n", hextotal);
            CANconversionlist[i].Data [1] = hextotal;
            part = tempstringB.substr(12,2);
            dealwithpart();
            //pc.printf("Hextotal obtained is %d.\r\n", hextotal);
            CANconversionlist[i].Data [2] = hextotal;
            part = tempstringB.substr(15,2);
            dealwithpart();
            //pc.printf("Hextotal obtained is %d.\r\n", hextotal);
            CANconversionlist[i].Data [3] = hextotal;
            part = tempstringB.substr(18,2);
            dealwithpart();
            //pc.printf("Hextotal obtained is %d.\r\n", hextotal);
            CANconversionlist[i].Data [4] = hextotal;
            part = tempstringB.substr(21,2);
            dealwithpart();
            //pc.printf("Hextotal obtained is %d.\r\n", hextotal);
            CANconversionlist[i].Data [5] = hextotal;
            part = tempstringB.substr(24,2);
            dealwithpart();
            //pc.printf("Hextotal obtained is %d.\r\n", hextotal);
            CANconversionlist[i].Data [6] = hextotal;
            part = tempstringB.substr(27,2);
            dealwithpart();
            //pc.printf("Hextotal obtained is %d.\r\n", hextotal);
            CANconversionlist[i].Data [7] = hextotal;
            }
        }
    }

//A function to handle key presses in tables mode
void tablesmodekeypress(void)
    {
    //pc.printf("Key press detected in tables mode!\r\n");
    if (c >= 48 and c <= 57)
        {
        numberkeypressed = c - 48;
        pc.printf("That's a number key press.('%d')\r\n", numberkeypressed);
        resetCANpairslist();
        if (numberkeypressed == 1)
            {
            CANpairslist[0].IDfrom = "301";
            CANpairslist[0].IDmessageto = "301 8 08 00 00 00 00 00 00 00";
            CANpairslist[1].IDfrom = "302";
            CANpairslist[1].IDmessageto = "302 8 06 07 00 00 00 00 00 00";
            CANpairslist[2].IDfrom = "303";
            CANpairslist[2].IDmessageto = "303 8 00 00 00 00 00 00 00 00";
            CANpairslist[3].IDfrom = "304";
            CANpairslist[3].IDmessageto = "304 8 08 00 00 00 00 00 00 00";
            CANpairslist[4].IDfrom = "305";
            CANpairslist[4].IDmessageto = "305 8 08 00 00 00 00 00 00 00";
            CANpairslist[5].IDfrom = "306";
            CANpairslist[5].IDmessageto = "306 8 02 03 00 00 00 00 00 00";
            CANpairslist[6].IDfrom = "307";
            CANpairslist[6].IDmessageto = "307 8 06 07 08 00 00 00 00 00";
            CANpairslist[7].IDfrom = "309";
            CANpairslist[7].IDmessageto = "308 8 06 07 08 00 00 00 00 00";
            }
        if (numberkeypressed == 2)
            {
            CANpairslist[0].IDfrom = "301";
            CANpairslist[0].IDmessageto = "401 8 08 00 00 00 04 05 06 01";
            CANpairslist[1].IDfrom = "302";
            CANpairslist[1].IDmessageto = "402 8 04 05 06 07 06 07 08 00";
            CANpairslist[2].IDfrom = "303";
            CANpairslist[2].IDmessageto = "403 8 03 04 05 05 06 80 00 00";
            CANpairslist[3].IDfrom = "304";
            CANpairslist[3].IDmessageto = "404 8 04 05 06 07 06 07 08 00";
            CANpairslist[4].IDfrom = "305";
            CANpairslist[4].IDmessageto = "405 8 04 05 06 07 06 07 08 00";
            CANpairslist[5].IDfrom = "306";
            CANpairslist[5].IDmessageto = "406 8 02 03 00 00 00 00 00 00";
            CANpairslist[6].IDfrom = "308";
            CANpairslist[6].IDmessageto = "408 8 06 07 08 00 00 00 00 00";
            CANpairslist[7].IDfrom = "309";
            CANpairslist[7].IDmessageto = "409 8 06 07 08 00 00 00 00 00";
            }
        if (numberkeypressed == 3)
            {
            CANpairslist[0].IDfrom = "317";
            CANpairslist[0].IDmessageto = "40A 8 08 00 00 00 04 05 06 07";
            CANpairslist[1].IDfrom = "318";
            CANpairslist[1].IDmessageto = "409 8 08 00 00 00 04 05 06 07";
            CANpairslist[2].IDfrom = "319";
            CANpairslist[2].IDmessageto = "408 8 06 07 02 03 04 05 00 00";
            CANpairslist[3].IDfrom = "31A";
            CANpairslist[3].IDmessageto = "407 8 08 00 00 00 04 05 02 03";
            CANpairslist[4].IDfrom = "31B";
            CANpairslist[4].IDmessageto = "40C 8 04 05 06 07 02 03 08 00";
            CANpairslist[5].IDfrom = "31C";
            CANpairslist[5].IDmessageto = "40B 8 06 07 04 05 02 03 00 00";
            CANpairslist[6].IDfrom = "31D";
            CANpairslist[6].IDmessageto = "406 8 08 00 00 00 04 05 06 07";
            CANpairslist[7].IDfrom = "31E";
            CANpairslist[7].IDmessageto = "405 8 04 05 06 07 00 00 00 00";
            CANpairslist[8].IDfrom = "324";
            CANpairslist[8].IDmessageto = "403 8 06 07 08 07 00 00 00 00";
            CANpairslist[9].IDfrom = "325";
            CANpairslist[9].IDmessageto = "404 8 04 05 06 07 00 00 00 00";
            CANpairslist[10].IDfrom = "329";
            CANpairslist[10].IDmessageto = "402 8 08 00 00 00 04 05 06 07";
            CANpairslist[11].IDfrom = "32A";
            CANpairslist[11].IDmessageto = "401 8 04 05 02 03 06 05 00 00";
            }
        gothroughCANpairslist();
        pc.printf("CAN conversion list currently has %d rows:\r\n", CANconversionlistheight);
        int i = 0;
        while (i < CANconversionlistheight)
            {
            //pc.printf("Printing row %d: ", i+1);
            pc.printf("ID \033[1;37m%03X\033[0m will convert to: \033[1;30;47m%03X %01X %02X %02X %02X %02X %02X %02X %02X %02X\033[0m", CANconversionlist[i].IDfrom, CANconversionlist[i].IDto, CANconversionlist[i].length, CANconversionlist[i].Data[0], CANconversionlist[i].Data[1], CANconversionlist[i].Data[2], CANconversionlist[i].Data[3], CANconversionlist[i].Data[4], CANconversionlist[i].Data[5], CANconversionlist[i].Data[6], CANconversionlist[i].Data[7]);
            pc.printf("\r\n");
            i++;
            }
        CANpassthrough = 0;
        pc.printf("CANpassthrough is now set to %d.\r\n", CANpassthrough);
        numberkeypressed = -1;
        }
    if (c == 27)
        {
        pc.printf("Leaving Expectation Table mode.\r\n");
        normalkeypresses = 1;
        tablesmode = 0;
        }
    }

//A function to report if baud rates differ
void reportbaudrates(void)
    {
    if (mbedCANbusspeed != CANGatewayCANbusspeed)
        {
        pc.printf("Mbed baud rate (%d) is different from assumed CAN Gateway baud rate (%d), will expect no CAN.\r\n", (mbedCANbusspeed / 1000), (CANGatewayCANbusspeed / 1000));
        }
    }

//A function to handle when CAN-expectations are not fulfilled
void expectationwasnotfulfilled(void)
    {
    //pc.printf("Expectation was not fulfilled for that message!\r\n");
    }

//A function to clear all test-related variables
void resetCANbuses()//A quick method to reset both CAN buses conveniently
    {
    CanBus.reset(); // Clear any bus errors. Will this stop the 'cached' CAN sticking around?
    CanBus2.reset(); // Clear any bus errors. Will this stop the 'cached' CAN sticking around?
    }

void resettest(void)
    {
    //pc.printf("Resetting test.\r\n");
    listen = 1;
    failsthistest = 0;
    failsstreak = 0;
    failsstreakstart = 0;
    spamcount = 0;
    noreplyfailsthistest = 0;
    goodnoreplies = 0;
    goodnoreplystreak = 0;
    goodnoreplystreakstartid = 0;
    noreplystreak = 0;
    noreplystreakstartid = 0;
    CANmatchstreak = 0;
    CANmatchstreakstartID = 0;
    mismatchfailsthistest = 0;
    matchesthistest = 0;
    idscheckedcount = 0;
    unexpectedCANfails = 0;
    unexpectedCANstreak = 0;
    unexpectedCANstreakstartid = 0;
    messagesincount = 0;
    testwasaborted = 0;
    }

//A function to add a carriage return in the output if the system has been writing out the CAN messages it sends.
void addnewlineifneeded(void)
{
    if (addnewlinetonextmessage == 1)
        {
        pc.printf("\r\n");
        addnewlinetonextmessage = 0;
        }
}

void reportsentCAN() //A function to print out the CAN that was sent. Messages can only be positioned correctly once their results are known.
    {    
    pc.printf("\033[1;33m\rSent out            : %s \033[0m", messageOutTextWithSpaces);
    }

    
//A function to end a test and report on findings.
void endtest()
    {
    listen = 0;
    expectationresolved = 1;
    if (testwasaborted == 1)
        {
        pc.printf("\033[1;35mTest was aborted, results invalid.\033[0m\r\n");
        pc.printf("\033[1;35m%d IDs sent out. %d failures found so far.\033[0m\r\n", spamcount, failsthistest);
        if (CANpassthrough == 0)
            {
            pc.printf("\033[1;35m%d expected non-replies found so far. \033[0m", goodnoreplies);
            }
        pc.printf("\033[1;35m%d CAN matches found so far.\033[0m\r\n", matchesthistest);
        }
    if (failsthistest == 0 and testwasaborted == 0)
        {
        pc.printf("\033[1;32mTest passed.\033[0m\r\n");
        pc.printf("\033[1;32m%d IDs sent out. \033[0m", spamcount);
        pc.printf("\033[1;32m%d failures found.\033[0m\r\n", failsthistest);
        if (CANpassthrough == 0)
            {
            pc.printf("\033[1;32m%d expected non-replies found. \033[0m", goodnoreplies);
            }
        pc.printf("\033[1;32m%d CAN matches found.\033[0m\r\n", matchesthistest);
        }
    if (failsthistest > 0 and testwasaborted == 0)
        {
        pc.printf("\033[1;31mTest failed.\r\n%d failures found.\033[0m\r\n", failsthistest);
        pc.printf("\033[1;31m%d mismatch failures, %d 'no reply' failures, %d unexpected CAN messages.\033[0m\r\n", mismatchfailsthistest, noreplyfailsthistest, unexpectedCANfails);
        if (goodnoreplies > 0)
            {
            pc.printf("\033[1;31m%d expected non-replies occurred.\033[0m\r\n", goodnoreplies);
            }
        }
    pc.printf("-------------------------------------\r\n");
    failsthistest = 0;
    normalkeypresses = 1;
    }

//'End ID spam test' function so you can end it by reaching 2048 IDs or pressing 'Esc' while it's running
void endidspamtest()
    {
    spamendtime = clock();
    getspamsecondstotal();//Process the spam information
    idspamon = 0;
    aspamisgoing = 0;
    normalkeypresses = 0;
    addnewlinetonextmessage = 1;
    //addnewlineifneeded();
    //pc.printf("Ending ID spam sequence. %d IDs checked total.\r\n", idscheckedcount);
    idlistincrementer = 0;
    endtest();
    }
    
void endspeedtest()//A different 'end' routine for speed tests.
    {
    //if (messagesincount == spamcount - 1)//If the messages in are only one less than messages out, adjust since it's probably just the test cancelling before getting that last message.
        //{
        //pc.printf("messagesincount is only one less than spamcount, setting it.\r\n");
        //messagesincount = spamcount;
        //}
    listen = 0;
    pc.printf("Ending CAN speed test.\r\n");
    pc.printf("%d messages sent. ", spamcount);
    pc.printf("%d messages detected coming back in over %d seconds.\r\n", messagesincount, spamsecondstotal);
    int speedtestpercentage = ((messagesincount * 100)/spamcount);
    int speedtestpasslevel = 90;
    if (speedtestpercentage >= speedtestpasslevel)
        {
        //pc.printf("\033[1;32mTest pass: %d%% of messages detected back.\033[0m\r\n\n", speedtestpercentage);
        }
    else
        {
        //pc.printf("\033[1;31mTest fail: %d%% of messages detected back.\033[0m\r\n\n", speedtestpercentage);
        }
    speedtestpasslevel = (CANGatewayCANbusspeed / 1000) * 8; //The HD2 can do 80 channels at 100Hz, so 8,000 messages per second are required at top baud rate (1000kbit/s)
    if (CANGatewayCANbusspeed == mbedCANbusspeed)
        {
        if (messagesinpersecond >= speedtestpasslevel)
            {
            pc.printf("\033[1;32mTest pass: %d messages in per second. (%d required for pass at Gateway baud rate %d.)\033[0m\r\n", messagesinpersecond, speedtestpasslevel, CANGatewayCANbusspeed / 1000);
            }
        if (messagesinpersecond < speedtestpasslevel)
            {
            pc.printf("\033[1;31mTest fail: %d messages in per second. (%d required for pass at Gateway baud rate %d.)\033[0m\r\n", messagesinpersecond, speedtestpasslevel, CANGatewayCANbusspeed / 1000);
            }
        }
    if (CANGatewayCANbusspeed != mbedCANbusspeed)
        {
        pc.printf("\033[1;35mTest invalid: Mbed CAN bus baud rate (%d) does not match presumed CAN Gateway baud rate (%d).\033[0m\r\n", mbedCANbusspeed / 1000, CANGatewayCANbusspeed / 1000);
        }
    pc.printf("\n");//Add an extra new line so the whole baud rate test is separate from the rest of the text.
    }

//A generic 'send CAN' function to send CAN with a standard message
void sendCAN(void)
{
    CanBus.write(messageOut1);
    //addnewlineifneeded();
    if (aspamisgoing == 0)
        {
        //pc.printf("\r\n");
        }
    expectationresolved = 0;
    //pc.printf("Expectationresolved now is %d.", expectationresolved);
    expectationtimer = 0;
    //addnewlinetonextmessage = 1;
}

//A function to get a coherent CAN message from one, uninterrupted string
void getCANfrommessageOutText(void)
{
    //pc.printf("messageOutText before space-removal is '%s'\r\n", messageOutText);
    messageOutTextWithSpaces = messageOutText;
    remove(messageOutText.begin(), messageOutText.end(), ' '); //Remove the spaces from the text to send out so it can be parsed.
    //pc.printf("After removing spaces, messageOutText is '%s'\r\n", messageOutText);
    string startofstring = messageOutText.substr(0,20); //Take the first 20 characters of the newly-formed string to get a spaceless CAN message.
    //pc.printf("String to parse is '%s'.\r\n", startofstring);
    expectationresolved = 0;
    if (expectationwasfulfilled == 0)
        {
        expectationwasnotfulfilled();
        }
    if (expectationwasfulfilled == -1)
        {
        expectationwasfulfilled = 0;
        }
    expectationwasfulfilled = 0;
    partincrement = 0;
    if (mbedCANbusspeed != CANGatewayCANbusspeed) // If the two bus speeds don't match, note that CAN should not be expected to ocme in and report the issue.
    {
    shouldntcomein = 1;
    if (aspamisgoing == 0)
        {
        reportbaudrates();
        }
    }
    part = startofstring.substr(0,3);
    dealwithpart();
    part = startofstring.substr(3,1);
    dealwithpart();
    part = startofstring.substr(4,2);
    dealwithpart();
    part = startofstring.substr(6,2);
    dealwithpart();
    part = startofstring.substr(8,2);
    dealwithpart();
    part = startofstring.substr(10,2);
    dealwithpart();
    part = startofstring.substr(12,2);
    dealwithpart();
    part = startofstring.substr(14,2);
    dealwithpart();
    part = startofstring.substr(16,2);
    dealwithpart();
    part = startofstring.substr(18,2);
    dealwithpart();
}

void displayhelp(void)
    {
    pc.printf("\033[1;32m---------------HELP---------------\r\n");
    pc.printf("Ken_CAN_Test is a program designed by Ken Dunlop to test CAN on the CAN Gateway.\r\n");
    pc.printf("The program is designed to send CAN, then test the response.\r\n");
    pc.printf("Press 'z' to begin sending a series of incrementing messages. Press 'Esc' to finish the test.\r\n");
    pc.printf("Press 'v' to send a message on all IDs (000 - 7FF). Press 'Esc' to abort the test.\r\n");
    pc.printf("Use 'q', 'w', 'e', and 'r' to change the Mbed's CAN bus speed.\r\n");
    pc.printf("Use 't', 'y', 'u', and 'i' to change the presumed CAN bus speed of the CAN Gateway.\r\n");
    pc.printf("If the two CAN bus speeds are different, the program will expect to get no CAN messages back.\r\n");
    pc.printf("Press 'a' to begin a baud rate test. This sends CAN messages quickly and measures how many come back.\r\n");
    pc.printf("Press 'k' to enter Custom Entry mode. This allows you to enter an CAN ID manually and then send a CAN message.\r\n");
    pc.printf("Press 'z' to begin sending incrementing CAN messages. The data in the message will increment by 1 each time.\r\n");
    pc.printf("Press 'o' while sending incrementing messages to multiply the incrementation by 16. This shifts the number up one half-byte.\r\n");
    pc.printf("Press 'k' to enter Custom Entry mode. This allows you to enter an CAN ID manually and then send a CAN message.\r\n");
    pc.printf("Press 'm' to set up an expectation table. This changes what CAN the system expects back when sending certain CAN IDs.\r\n");
    pc.printf("Press 'n' to cancel the expectation table and re-enter CAN passthrough mode. This will simply expect the same CAN back as was sent.\r\n");
    pc.printf("Press the number keys from '1' to '0' to send various pre-defined CAN messages out.\r\n");
    pc.printf("Press '?' to bring up this help screen!\r\n");
    pc.printf("---------------------------------\033[0m\r\n");
    }

void printMessageOut (void)
{
    //This function will print out whatever the CAN bus is sending out. Can't be used constantly as it sends '000 8 00 00 00 00 00 00 00 00' all the time.
    pc.printf("Message OUT: %03X %01X %02X %02X %02X %02X %02X %02X %02X %02X\r\n",messageOut1.id,messageOut1.len,messageOut1.data[0],messageOut1.data[1],messageOut1.data[2],messageOut1.data[3],messageOut1.data[4],messageOut1.data[5],messageOut1.data[6],messageOut1.data[7]);
}

void printMessageIn (void)
{
    //This function will print out whatever the CAN bus is receiving.
    //addnewlineifneeded();
    pc.printf("\033[0;36mMessage IN: %03X %01X %02X %02X %02X %02X %02X %02X %02X %02X\033[0m\r\n",messageIn.id,messageIn.len,messageIn.data[0],messageIn.data[1],messageIn.data[2],messageIn.data[3],messageIn.data[4],messageIn.data[5],messageIn.data[6],messageIn.data[7]);
}

//The 'main' function will run as soon as the program starts.
int main()
{
    pc.baud(115200); // serial port at 115200
    CanBus.frequency(500 * 1000); // CAN bus at 500k
    CanBus2.frequency(500 * 1000); // CAN bus at 500k
    CanBus.reset(); // clear any bus errors
    CanBus2.reset(); // clear any bus errors
    //NOTE: Print messages must be below this line to work.
    pc.printf("\033[0m------------------------------------------\r\n");
    pc.printf("Welcome to Ken CAN test.\r\n");
    pc.printf("Setting CAN bus to 500k.\r\n");
    pc.printf("Setting serial port to baud rate 115200.\r\n");
    pc.printf("Using pins 9 and 10 for CANBus 1 (out) and 30 and 29 for CANBus 2 (in).\r\n");
    pc.printf("Version %d.%d\r\n",kMajorVersion,kMinorVersion);
    pc.printf("Build date %s %s\r\n",__DATE__,__TIME__);
    pc.printf("\033[1;32mFor help, press '?'.\033[0m\r\n");
    pc.printf("------------------------------------------\r\n");
    //char c;
    
    //Check for button presses
    while (1)
    {
    if (expectationtimer < 100 and expectationresolved == 0)
    {
        if (expectationresolved == 0)
        {
            expectationtimer++;
            if (expectationtimer >= 2)//If expectation timer gets too high, the CAN reply is deemed not to have arrived.
                {
                if (CANmatchstreak > 0) //CAN not arriving breaks any CAN match streak
                    {
                    CANmatchstreak = 0;
                    CANmatchstreakstartID = 0;
                    if (aspamisgoing == 1)
                        {
                        pc.printf("\r\n\nFrombreakingCANmatchstreak");//Add a return into the terminal to show the old streak on a line by itself.
                        }
                    }
                if (goodnoreplystreak > 0 and shouldntcomein == 0) //A missing expected reply breaks any combos for expected no-replies
                    {
                    if (aspamisgoing == 1)
                        {
                        //pc.printf("\r\n(From breaking goodnoreplystreak)\n\r");
                        pc.printf("\r\n\n");
                        }
                    goodnoreplystreak = 0;
                    goodnoreplystreakstartid = 0;
                    }
                // If data did not come in when it was expected...
                if (shouldntcomein == 0)
                    {
                    expectationwasfulfilled = 0;
                    failsthistest++;
                    noreplyfailsthistest++;
                    if (aspamisgoing == 0)
                        {
                        noreplystreakstartid = idlistincrementer;
                        }
                    if (goodnoreplystreak > 0)
                        {
                        goodnoreplystreak = 0;
                        if (aspamisgoing == 1)
                            {
                            pc.printf("(\r\n\n");//Add an extra line if breaking an 'as expected' no reply streak.
                            }
                        }
                    if (failsstreak > 0)
                        {
                        if (aspamisgoing == 1)
                            {
                            pc.printf("\r\n\n");//Add an extra line if breaking a failure 'does not match expectation' streak
                            }
                        failsstreak = 0;
                        failsstreakstart = 0;
                        }
                    if (aspamisgoing == 1)
                        {
                        if (noreplystreak == 0)
                            {
                            noreplystreakstartid = idlistincrementer;
                            }
                        noreplystreak++;
                        }
                    reportsentCAN();//Now that it's known the CAN has no reply, you can safely write out the sent CAN. (The needed line-returns have been added.)
                    if (noreplystreakstartid != idlistincrementer)
                        {
                        pc.printf("\033[38;5;220mNo reply message detected for IDs %03X to %03X.\033[0m\r", noreplystreakstartid, idlistincrementer);
                        }
                    if (noreplystreakstartid == idlistincrementer)
                        {
                        pc.printf("\033[38;5;220mNo reply message detected for ID %03X.\033[0m\r", idlistincrementer);
                        }
                    if (aspamisgoing == 0)
                        {
                        pc.printf("\r\n\n"); //If it's not spamming, you can safely add a new line after the fail message.
                        }
                    }
                if (shouldntcomein == 1)
                    {
                    expectationwasfulfilled = 1;
                    //Getting an expected non-reply breaks any unexpected reply streaks
                    if (unexpectedCANstreak > 0)
                        {
                            if (aspamisgoing == 1) //Add a new line if it's in spam mode here to report new expected-non-message stuff.
                                {
                                //pc.printf("\r\n\n(FrombreakingunexpectedCANstreak)");
                                pc.printf("\r\n\n");
                                }
                        unexpectedCANstreak = 0;
                        unexpectedCANstreakstartid = 0;
                        }
                    //Getting an expected non-reply also breaks any unexpected non-reply streaks
                    if (noreplystreak > 0)
                        {
                            if (aspamisgoing == 1) //Add a new line if it's in spam mode here to report new expected-non-message stuff.
                                {
                                //pc.printf("\r\n(From breaking noreplystreak)\n");
                                pc.printf("\r\n\n");
                                }
                        noreplystreak = 0;
                        noreplystreakstartid = 0;
                        }
                    // Also, getting an expected non-reply breaks any CAN-fail streaks
                    if (failsstreak > 0 )
                        {
                        if (aspamisgoing == 1)
                            {
                            //pc.printf("\r\n(From breaking CAN-mismatch streak)\n");
                            pc.printf("\r\n\n");
                            }
                        failsstreak = 0;
                        failsstreakstart = 0;
                        }
                    if (goodnoreplystreak == 0) //If there isn't yet a good no-reply streak, set the starting no-reply ID to this one
                        {
                        goodnoreplystreakstartid = idlistincrementer;
                        if (CANmatchstreak > 0 and aspamisgoing == 1)//Also add an extra return for the breaking of the old CANmatchstreak if needed
                            {
                            CANmatchstreak = 0;
                            pc.printf("(From breaking of CANmatchstreak)\r\n");
                            }
                        }
                    reportsentCAN();//Now that it's known the CAN has no reply, you can safely write out the sent CAN. (The needed line-returns have been added.)
                    if (aspamisgoing == 0)
                        {
                        goodnoreplystreakstartid = idlistincrementer;
                        }
                    if (goodnoreplystreakstartid != idlistincrementer)
                        {
                        pc.printf("\033[0;32mNo reply message detected from %03X to %03X, as expected.\033[0m\r", goodnoreplystreakstartid, idlistincrementer);
                        }
                    if (goodnoreplystreakstartid == idlistincrementer)
                        {
                        pc.printf("\033[0;32mNo reply message detected for ID %03X, as expected.\033[0m\r", goodnoreplystreakstartid);
                        }
                    if (aspamisgoing == 0)
                        {
                        pc.printf("\r\n\n"); //If it's not spamming, you can safely add a new line after the fail message.
                        }
                    goodnoreplies++;
                    goodnoreplystreak++;
                    }
                expectationresolved = 1;
                //pc.printf("Expectation timer reached %d!\r\n", expectationtimer);
                expectationtimer = 0;
                if (idspamon == 1)
                    {
                    idscheckedcount++;
                    idlistincrementer++; //Only add 1 to the idlist incrementer at the end so the first ID it sends is '000'.
                    }
                if (customentry == 1)
                    {
                    pc.printf("Enter CAN ID to send: ");
                    }
                }
            wait(0.01);
        }
    }
        if (pc.readable())
        {
            c = tolower(pc.getc());
            if (c != NULL)
            {
                //When the a key is pressed, define a CAN message and send it.
                //pc.printf("A key was pressed! (%c)\r\n", c);
                messageOutText = "";
                buttonPressMessageOutText = "";
                if (c == '1' and normalkeypresses == 1)
                    {
                    buttonPressMessageOutText = "301 8 01 02 03 04 05 06 07 08";
                    idlistincrementer = 0x301;
                    }
                if (c == '2' and normalkeypresses == 1)
                    {
                    buttonPressMessageOutText = "302 8 01 02 03 04 05 06 07 08";
                    idlistincrementer = 0x302;
                    }
                if (c == '3' and normalkeypresses == 1)
                    {
                    buttonPressMessageOutText = "303 8 01 02 03 04 05 06 07 08";
                    idlistincrementer = 0x303;
                    }
                if (c == '4' and normalkeypresses == 1)
                    {
                    buttonPressMessageOutText = "304 8 01 02 03 04 05 06 07 08";
                    idlistincrementer = 0x304;
                    }
                if (c == '5' and normalkeypresses == 1)
                    {
                    buttonPressMessageOutText = "305 8 01 02 03 04 05 06 07 08";
                    idlistincrementer = 0x305;
                    }
                if (c == '6' and normalkeypresses == 1)
                    {
                    buttonPressMessageOutText = "306 8 01 02 03 04 05 06 07 08";
                    idlistincrementer = 0x306;
                    }
                if (c == '7' and normalkeypresses == 1)
                    {
                    buttonPressMessageOutText = "307 8 01 02 03 04 05 06 07 08";
                    idlistincrementer = 0x307;
                    }
                if (c == '8' and normalkeypresses == 1)
                    {
                    buttonPressMessageOutText = "308 8 01 02 03 04 05 06 07 08";
                    idlistincrementer = 0x308;
                    }
                if (c == '9' and normalkeypresses == 1)
                    {
                    buttonPressMessageOutText = "309 8 01 02 03 04 05 06 07 08";
                    idlistincrementer = 0x309;
                    }
                if (c == '0' and normalkeypresses == 1)
                    {
                    buttonPressMessageOutText = "7FF 8 FF FF FF FF FF FF FF FF";//NOTE: CAN IDs only go to 7FF, not FFF.
                    idlistincrementer = 0x7FF;
                    }
                if (c == 'a' and normalkeypresses == 1)
                    {
                    listen = 1;
                    pc.printf("Starting baud rate speed test. Mbed at %d and CAN Gateway presumed %d. (Press 'Esc' to end.)\r\n", mbedCANbusspeed / 1000, CANGatewayCANbusspeed / 1000);
                    pc.printf("");
                    resettest();
                    incrementer = 0x333;
                    spamstarttime = clock();
                    speedspamison = 1;
                    aspamisgoing = 1;
                    normalkeypresses = 0;
                    messageOut1.format = CANStandard; //Quickly define a convenient messageOut for the speed spam to use.
                    messageOut1.id = 0x301;
                    messageOut1.len = 8;
                    messageOut1.data[0] = 0x06;
                    messageOut1.data[1] = 0x3f;
                    messageOut1.data[2] = 0xb2;
                    messageOut1.data[3] = 0x29;
                    messageOut1.data[4] = 0x19;
                    messageOut1.data[5] = 0x97;
                    messageOut1.data[6] = 0x67;
                    messageOut1.data[7] = 0x37;
                    pc.printf("Will send out '%03X %01X %02X %02X %02X %02X %02X %02X %02X %02X' as fast as possible.\r\n", messageOut1.id, messageOut1.len, messageOut1.data[0], messageOut1.data[1], messageOut1.data[2], messageOut1.data[3], messageOut1.data[4], messageOut1.data[5], messageOut1.data[6], messageOut1.data[7]);
                    }
                if (c == 27 and speedspamison == 1)//Cancel speed spam mode
                    {
                    //pc.printf("\r\nEnding baud rate speed test mode from upper key press method.\r\n");
                    aspamisgoing = 0;
                    normalkeypresses = 1;
                    spamendtime = clock();
                    //endtest();
                    getspamsecondstotal();
                    endspeedtest();
                    speedspamison = 0;
                    }
                if (buttonPressMessageOutText != "")//Centralized 'button press MessageOut' routine that applies to all button presses.
                    {
                    if (aspamisgoing == 0)
                        {
                        //addnewlineifneeded();
                        //resetCANbuses();
                        listen = 1;
                        messageOutText = buttonPressMessageOutText;
                        addnewlinetonextmessage = 1;
                        checklaterbytes = 1;//Check all bytes for button-press messages.
                        }
                    buttonPressMessageOutText = "";
                    }
                if (c == '/' and normalkeypresses == 1)
                    {
                    displayhelp();
                    }
                if (c == '?' and normalkeypresses == 1)
                    {
                    displayhelp();
                    }
                if (c == 'q' and normalkeypresses == 1)
                    {
                    pc.printf("Changing Mbed CAN bus speed to 125.\r\n");
                    CanBus.frequency(125 * 1000); // CAN bus at 125k
                    CanBus2.frequency(125 * 1000); // CAN bus at 125k
                    mbedCANbusspeed = (125 * 1000);
                    }
                if (c == 'w' and normalkeypresses == 1)
                    {
                    pc.printf("Changing Mbed CAN bus speed to 250.\r\n");
                    CanBus.frequency(250 * 1000); // CAN bus at 250k
                    CanBus2.frequency(250 * 1000); // CAN bus at 250k
                    mbedCANbusspeed = (250 * 1000);
                    }
                if (c == 'e' and normalkeypresses == 1)
                    {
                    pc.printf("Changing Mbed CAN bus speed to 500.\r\n");
                    CanBus.frequency(500 * 1000); // CAN bus at 500k
                    CanBus2.frequency(500 * 1000);// CAN bus at 500k
                    mbedCANbusspeed = (500 * 1000);
                    }
                if (c == 'r' and normalkeypresses == 1)
                    {
                    pc.printf("Changing Mbed CAN bus speed to 1000.\r\n");
                    CanBus.frequency(1000 * 1000); // CAN bus at 1000k
                    CanBus2.frequency(1000 * 1000); // CAN bus at 1000k
                    mbedCANbusspeed = (1000 * 1000);
                    }
                if (c == 't' and normalkeypresses == 1)
                    {
                    CANGatewayCANbusspeed = (125 * 1000);
                    pc.printf("CAN Gateway is now presumed to be at CAN bus speed %d.\r\n", CANGatewayCANbusspeed / 1000);
                    }
                if (c == 'y' and normalkeypresses == 1)
                    {
                    CANGatewayCANbusspeed = (250 * 1000);
                    pc.printf("CAN Gateway is now presumed to be at CAN bus speed %d.\r\n", CANGatewayCANbusspeed / 1000);
                    }
                if (c == 'u' and normalkeypresses == 1)
                    {
                    CANGatewayCANbusspeed = (500 * 1000);
                    pc.printf("CAN Gateway is now presumed to be at CAN bus speed %d.\r\n", CANGatewayCANbusspeed / 1000);
                    }
                if (c == 'i' and normalkeypresses == 1)
                    {
                    CANGatewayCANbusspeed = (1000 * 1000);
                    pc.printf("CAN Gateway is now presumed to be at CAN bus speed %d.\r\n", CANGatewayCANbusspeed / 1000);
                    }
                if (c == 'k' and normalkeypresses == 1)
                    {
                    pc.printf("Will enter custom CAN entry mode. (Press 'Esc' to end.)\r\nEnter CAN ID to send: ");
                    customentry = 1;
                    normalkeypresses = 0;
                    c = NULL;
                    customentrystring = "";
                    }
                if (c == 27 and customentry == 1)//Pressing Esc ends Custom Entry mode
                    {
                    customentry = 0;
                    normalkeypresses = 1;
                    pc.printf("\r\nEnding custom entry mode.\r\n");
                    c = NULL;
                    }
                if (c == 13 and customentry == 1 and customentrystring != "")//Pressing enter in Custom Entry mode tries to send a CAN message
                    {
                    pc.printf("\r\n");
                    //pc.printf("Will try to confirm CES ('%s').\r\n", customentrystring);
                    if (customentrystring.length() < 3)
                        {
                        customentrystring = "0" + customentrystring;
                        }
                    if (customentrystring.length() < 3)
                        {
                        customentrystring = "0" + customentrystring;
                        }
                    checklaterbytes = 1;
                    partincrement = 0;
                    part = customentrystring;
                    dealwithpart();
                    //pc.printf("Hextotal now says '%d'.\r\n", hextotal);
                    if (hextotal > 0x7FF)//If the measured total is more than 0x7FF (the max ID), reduce it.
                        {
                        hextotal = 0x7FF;
                        customentrystring = "7FF";
                        }
                    if (hextotal < 0) // If the measured total is less than zero, make it zero instead.
                        {
                        hextotal = 0x000;
                        customentrystring = "000";
                        }
                    messageOutText = customentrystring + " 8 01 02 03 04 05 06 07 08";
                    customentrystring = "";
                    if (expectationresolved == 1 and messageOutText == "")
                        {
                        pc.printf("Enter CAN ID to send: ");
                        }
                    }
                if (c != NULL and customentry == 1 and expectationresolved == 1 and messageOutText == "")
                    {
                    //pc.printf("Custom entry detected! (%c)\r\n", c);
                    if (c != '\r' and c != 8 and customentrystring.length() < 3) //Normal key presses add to the custom string.
                        {
                        customentrystring.push_back(toupper(c));
                        //pc.printf("Custom entry string now says '%s'.", customentrystring);
                        }
                    if (c == 8 and customentrystring.length() > 0) //Backspace (character 8) causes the text to go back one character.
                        {
                        pc.printf("\b ");
                        customentrystring.erase(customentrystring.size()-1,1);
                        }
                    pc.printf("\rEnter CAN ID to send: %s", customentrystring);
                    }
                if (c == 'n' and CANpassthrough == 0 and normalkeypresses == 1)
                    {
                    pc.printf("Starting CAN passthrough mode. Will expect to recieve the same CAN that is sent.\r\n");
                    CANpassthrough = 1;
                    }
                if (c == 'm' and normalkeypresses == 1) //New menu to select multiple expectation tables
                    {
                    normalkeypresses = 0; //Go out of 'normal key presses' mode.
                    pc.printf("Now entering Expectation Table mode. Press the number keys to activate different expectation tables.\r\n");
                    tablesmode = 1;
                    }
                if (c != NULL and tablesmode == 1)
                    {
                    tablesmodekeypress();
                    }
                if (c == 'o' and idspamon == 0 and spamon == 1)
                    {
                    incrementer = (incrementer * 16);
                    pc.printf("\n\rMultiplied Incrementer by 16. It's now %d.\r\n", incrementer);
                    }
                if (c == 'i' and spamon == 1)
                    {
                    incrementer = incrementer + 16;
                    std::stringstream sstream;
                    sstream << std::hex << incrementer;
                    string stringsofar = sstream.str();
                    //pc.printf("Incrementer is now %d.\r\n", incrementer);
                    //pc.printf("StringStream says '%s'.\r\n", stringsofar);
                    int length = stringsofar.length();
                    //pc.printf("Length is %d/16.\r\n", length);
                    for (int i = 0; i < (16-length); i++)
                        stringsofar = "0" + stringsofar;
                    //pc.printf("stringsofar says '%s'.\r\n", stringsofar);
                    //messageOutText = "305 8 " + stringsofar;
                    //pc.printf("Will try to send '%s'.\r\n", messageOutText);
                    }
                messageOut1.format = CANStandard;
                if (c == 'z' and normalkeypresses == 1)
                    {
                    resettest();
                    pc.printf("Starting spam sequence for ID %s. Press 'Esc' to end. Press 'o' to increase incrementer.\r\n", spampreamble);
                    idlistincrementer = 0x333;
                    reportbaudrates();
                    spamon = 1;
                    aspamisgoing = 1;
                    normalkeypresses = 0;
                    checklaterbytes = 1;
                    incrementer = 0;
                    spamcount = 0;
                    spamstarttime = clock();
                    //pc.printf("Spam start time is %d.\r\n", spamstarttime);
                    }
                if (c == 27 and spamon == 1)//Cancel normal '333' incrementing spam mode
                    {
                    pc.printf("\r\n");
                    spamon = 2;
                    aspamisgoing = 0;
                    normalkeypresses = 1;
                    spamendtime = clock();
                    getspamsecondstotal();//Process the spam information
                    //pc.printf("Total spams ever are %d.\r\n", totalspamsever);
                    endtest();
                    //pc.printf("-------------------------\r\n");
                    }
                if (c == 27 and idspamon ==  1)//Cancel CAN ID spam mode
                    {
                    //pc.printf("Cancelling ID test mode.\r\n");
                    testwasaborted = 1;
                    endidspamtest();
                    normalkeypresses = 1;
                    }
                if (c == 'v' and normalkeypresses == 1)
                    {
                    resettest();
                    idspamon = 1; //Set the 'idspamon' integer to 1 so ID spam happens.
                    aspamisgoing = 1;
                    normalkeypresses = 0;
                    checklaterbytes = 1;
                    idlistincrementer = 0;
                    pc.printf("Beginning check of all possible CAN IDs (000 - 7FF). Press 'Esc' to abort.\r\n");
                    reportbaudrates();
                    spamstarttime = clock();
                    //pc.printf("Spam started at clock time %d.\r\n", spamstarttime);
                    if (checklaterbytes == 0)
                        {
                        pc.printf("Will only check CAN IDs, not later bytes.\r\n");
                        }
                    if (checklaterbytes == 1)
                        {
                        pc.printf("Will check all bytes in each CAN message.\r\n");
                        }
                    }
                if (messageOutText != "" and speedspamison == 0)
                    {
                    getCANfrommessageOutText();
                    sendCAN();
                    //CanBus.write(messageOut1);
                    //CanBus2.write(messageOut1);
                    if (spamon == 0 and idspamon == 0)
                        {
                        //printMessageOut();
                        }
                    messageOutText = "";
                    }
                }
        }

        
                //If spam mode is on, spam an incrementing CAN message
                if (spamon == 1 and expectationresolved == 1)
                    {
                    spamcount ++;
                    totalspamsever ++;
                    incrementer ++;
                    std::stringstream sstream;
                    sstream << std::hex << incrementer;
                    string stringsofar = sstream.str();
                    int length = stringsofar.length();
                    for (int i = 0; i < (16-length); i++)
                    stringsofar = "0" + stringsofar;
                    messageOutText = spampreamble + " 8 " + stringsofar;
                    getCANfrommessageOutText();
                    sendCAN();
                    }
                if (idspamon == 1 and idlistincrementer >= 2048 and expectationresolved == 1) //If the spam value gets to 2048 (7FF), end the spam sequence. RL only go up to 7FF.
                    {
                       endidspamtest();
                    }
                if (idspamon == 1 and expectationresolved == 1)
                    {
                    spamcount++;
                    std::stringstream sstream;
                    sstream << std::hex << idlistincrementer;
                    string idstring = "";
                    idstring = sstream.str();
                    //pc.printf("idstring says '%s'\r\n", idstring);
                    if (idstring.length() < 3)
                        {
                        for (int i = 0; i < (4 - idstring.length()); i++)
                            {
                            idstring = "0" + idstring;
                            }
                        }
                    //pc.printf("idstring now says '%s'\r\n", idstring);
                    //pc.printf("%s\r\n", idstring);
                    idstring = idstring + " 8 01 02 03 04 05 06 07 08";
                    //pc.printf("...and now idstring now says '%s'\r\n", idstring);
                    messageOutText = idstring;
                    getCANfrommessageOutText();
                    sendCAN();
                    //CanBus.write(messageOut1);
                    //CanBus2.write(messageOut1);
                    //pc.printf("ID list incrementer is now %d\r\n", idlistincrementer);
                    wait(0.01);//ID spam at 100Hz
                    }

        //Optional: mention any un-listened-to CAN messages. Having this stopped it from reading messages in when listen was on.
        //if (CanBus2.read(messageIn) and listen == 0)
        //  {
        //  pc.printf("(Un-listened-to CAN message came in.)\r\n");
        //  }

        //Check for CAN messages coming in
        if (CanBus2.read(messageIn) and listen == 1)
            {
            if (speedspamison == 1)
                {
                messagesincount++;
                //pc.printf("\033[0;36m Speed spam message IN: %03X %01X %02X %02X %02X %02X %02X %02X %02X %02X\033[0m\r\n",messageIn.id,messageIn.len,messageIn.data[0],messageIn.data[1],messageIn.data[2],messageIn.data[3],messageIn.data[4],messageIn.data[5],messageIn.data[6],messageIn.data[7]);
                }
            if (speedspamison == 0)
                {
                //pc.printf("\033[0;36mNormal message IN: %03X %01X %02X %02X %02X %02X %02X %02X %02X %02X\033[0m\r\n",messageIn.id,messageIn.len,messageIn.data[0],messageIn.data[1],messageIn.data[2],messageIn.data[3],messageIn.data[4],messageIn.data[5],messageIn.data[6],messageIn.data[7]);
                if (noreplystreak > 0)
                    {
                    noreplystreak = 0;
                    noreplystreakstartid = 0;
                    pc.printf("\r\n\n");
                    }
                if (goodnoreplystreak > 0)
                    {
                    goodnoreplystreak = 0;
                    goodnoreplystreakstartid = 0;
                    if (aspamisgoing == 1)
                        {
                        pc.printf("\r\n\n");
                        }
                    }
                CANCount++;
                if (1 == 1)//Prepare to print out the message coming in
                    {
                    //Data shouldn't come in at all if 'shouldntcomein' is 1!
                    //pc.printf("Wah! Unexpected CAN came in!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\r\n");
                    if (shouldntcomein == 1)
                        {
                        if (failsstreak > 0)
                            {
                            failsstreak = 0;
                            failsstreakstart = 0;
                            if (aspamisgoing == 1)
                                {
                                pc.printf("\n\n\r");
                                }
                            }
                        if (unexpectedCANstreak == 0)//If it's the start of a new unexpected-CAN streak, mark the starting ID.
                            {
                            unexpectedCANstreakstartid = idlistincrementer;
                            }
                        if (aspamisgoing == 0)
                            {
                            unexpectedCANstreakstartid = idlistincrementer;
                            }
                        reportsentCAN();
                        if (unexpectedCANstreakstartid != idlistincrementer)
                            {
                            pc.printf("\033[0;35mUnexpected data came in for IDs %03X to %03X!\033[0m", unexpectedCANstreakstartid, idlistincrementer);
                            }
                        if (unexpectedCANstreakstartid == idlistincrementer)
                            {
                            pc.printf("\033[0;35mUnexpected data came in for %03X!\033[0m", idlistincrementer);
                            }
                        failsthistest++;
                        unexpectedCANfails++;
                        unexpectedCANstreak++;
                        }
                    //Establish earlier whether it's a match in the 10 places
                    int itsamatch = 1;
                    if (expected1 != messageIn.id)
                        {itsamatch = 0;}
                    if (expected2 != messageIn.len and checklaterbytes >= 1)
                        {itsamatch = 0;}
                    if (expected3 != messageIn.data[0] and checklaterbytes >= 1)
                        {itsamatch = 0;}
                    if (expected4 != messageIn.data[1] and checklaterbytes >= 1)
                        {itsamatch = 0;}
                    if (expected5 != messageIn.data[2] and checklaterbytes >= 1)
                        {itsamatch = 0;}
                    if (expected6 != messageIn.data[3] and checklaterbytes >= 1)
                        {itsamatch = 0;}
                    if (expected7 != messageIn.data[4] and checklaterbytes >= 1)
                        {itsamatch = 0;}
                    if (expected8 != messageIn.data[5] and checklaterbytes >= 1)
                        {itsamatch = 0;}
                    if (expected9 != messageIn.data[6] and checklaterbytes >= 1)
                        {itsamatch = 0;}
                    if (expected10 != messageIn.data[7] and checklaterbytes >= 1)
                        {itsamatch = 0;}

                    if (itsamatch == 0 and shouldntcomein == 0)
                        {
                        if (goodnoreplystreak > 0)
                            {
                            goodnoreplystreak = 0;
                            goodnoreplystreakstartid = 0;
                            if (aspamisgoing == 1)
                                {
                                pc.printf("\r\n\n");
                                }
                            }
                        if (CANmatchstreak > 0)
                            {
                            CANmatchstreak = 0;
                            CANmatchstreakstartID = 0;
                            if (aspamisgoing == 1)
                                {
                                pc.printf("\r\n\n");
                                }
                            }
                        if (failsstreak == 0)
                            {
                            failsstreakstart = idlistincrementer;
                            }
                        failsstreak++;
                        if (aspamisgoing == 0)
                            {
                            failsstreakstart = idlistincrementer;
                            }
                        reportsentCAN(); //Report sent CAN before any 'does not match...' messages
                        if (failsstreakstart == idlistincrementer)
                            {
                            pc.printf("\033[0;31mData for ID %03X does not match expectation!\033[0m", idlistincrementer);
                            }
                        if (failsstreakstart != idlistincrementer)
                            {
                            pc.printf("\033[0;31mData for IDs %03X to %03X does not match expectation!\033[0m", failsstreakstart, idlistincrementer);
                            }
                        }
                    //Decide if a message in will need to be printed ('Message received was:...')
                    messageinisneeded = 0;
                    if (aspamisgoing == 0)
                        {messageinisneeded = 1;}
                    if (itsamatch == 0 and shouldntcomein == 0 and reportfailsindividually == 1)
                        {messageinisneeded = 1;}
                    // If a message in is destined to be printed, reset the failsstreak if needed
                    if (messageinisneeded == 1 and failsstreak > 0)
                        {
                        failsstreak = 0;
                        failsstreakstart = 0;
                        }
                    // Once it's known whether the data matches expectation, set the match streak
                    if (itsamatch == 1 and shouldntcomein == 0)
                        {
                        if (failsstreak > 0)
                            {
                            failsstreak = 0;
                            failsstreakstart = 0;
                            if (aspamisgoing == 1)
                                {
                                pc.printf("\r\n\n");
                                }
                            }
                        if (CANmatchstreak == 0)
                            {
                            CANmatchstreakstartID = idlistincrementer;
                            }
                        CANmatchstreak++;
                        }
                    if (itsamatch == 0 and CANmatchstreak > 0) //If it's NOT a match, break any CANmatchstreak
                        {
                        CANmatchstreak = 0;
                        CANmatchstreakstartID = 0;
                        }
                    // Print needed message
                    reportsentCAN();
                    if (messageinisneeded == 0) //If a message in is NOT needed, simply report what the CAN is doing on the same line.
                        {
                        if (itsamatch == 1 and CANmatchstreakstartID == idlistincrementer and CANmatchstreak > 0)
                            {
                            pc.printf("\033[0;32mCAN matches expected values on ID %03X.\033[0m", idlistincrementer);
                            }
                        if (itsamatch == 1 and CANmatchstreakstartID != idlistincrementer and CANmatchstreak > 0)
                            {
                            pc.printf("\033[0;32mCAN matches expected values from IDs %03X to %03X.\033[0m", CANmatchstreakstartID, idlistincrementer);
                            }
                        }
                    if (messageinisneeded == 1) //Only if message in is needed do you need to look at printing each part of the message
                        {
                        pc.printf("\r\nMessage received was: ");
                        if (expected1 != messageIn.id)
                            {
                            //pc.printf("\r\nID of %d does NOT match %d.\r\n", messageIn.id, expected1);
                            pc.printf("\033[1;31m%03X\033[0m ", messageIn.id);//Show the ID in red if it doesn't match.
                            }
                        if (expected1 == messageIn.id)
                            {
                            pc.printf("\033[1;32m%03X\033[0m ", messageIn.id);//Show the ID in green if it matches.
                            }
                        if (expected2 != messageIn.len and checklaterbytes >= 1)
                            {
                            //pc.printf("Length of %d does NOT match %d.\r\n", messageIn.len, expected2);
                            pc.printf("\033[1;31m%01X\033[0m ", messageIn.len);
                            }
                        else
                            {
                            pc.printf("\033[1;32m%01X\033[0m ", messageIn.len);
                            }
                        if (expected3 != messageIn.data[0] and checklaterbytes >= 1)
                            {
                            //pc.printf("Data 0 of %d does NOT match %d.\r\n", messageIn.data[0], expected3);
                            pc.printf("\033[1;31m%02X\033[0m ", messageIn.data[0]);
                            }
                        else
                            {
                            pc.printf("\033[1;32m%02X\033[0m ", messageIn.data[0]);
                            }
                        if (expected4 != messageIn.data[1] and checklaterbytes >= 1)
                            {
                            //pc.printf("Data 1 of %d does NOT match %d.\r\n", messageIn.data[1], expected4);
                            pc.printf("\033[1;31m%02X\033[0m ", messageIn.data[1]);
                            }
                        else
                            {
                            pc.printf("\033[1;32m%02X\033[0m ", messageIn.data[1]);
                            }
                        if (expected5 != messageIn.data[2] and checklaterbytes >= 1)
                            {
                            //pc.printf("Data 2 of %d does NOT match %d.\r\n", messageIn.data[2], expected5);
                            pc.printf("\033[1;31m%02X\033[0m ", messageIn.data[2]);
                            }
                        else
                            {
                            pc.printf("\033[1;32m%02X\033[0m ", messageIn.data[2]);
                            }
                        if (expected6 != messageIn.data[3] and checklaterbytes >= 1)
                            {
                            //pc.printf("Data 3 of %d does NOT match %d.\r\n", messageIn.data[3], expected6);
                            pc.printf("\033[1;31m%02X\033[0m ", messageIn.data[3]);
                            }
                            
                        else
                            {
                            pc.printf("\033[1;32m%02X\033[0m ", messageIn.data[3]);
                            }
                        if (expected7 != messageIn.data[4] and checklaterbytes >= 1)
                            {
                            //pc.printf("Data 4 of %d does NOT match %d.\r\n", messageIn.data[4], expected7);
                            pc.printf("\033[1;31m%02X\033[0m ", messageIn.data[4]);
                            }
                        else
                            {
                            pc.printf("\033[1;32m%02X\033[0m ", messageIn.data[4]);
                            }
                        if (expected8 != messageIn.data[5] and checklaterbytes >= 1)
                            {
                            //pc.printf("Data 5 of %d does NOT match %d.\r\n", messageIn.data[5], expected8);
                            pc.printf("\033[1;31m%02X\033[0m ", messageIn.data[5]);
                            }
                        else
                            {
                            pc.printf("\033[1;32m%02X\033[0m ", messageIn.data[5]);
                            }
                        if (expected9 != messageIn.data[6] and checklaterbytes >= 1)
                            {
                            //pc.printf("Data 6 of %d does NOT match %d.\r\n", messageIn.data[6], expected9);
                            pc.printf("\033[1;31m%02X\033[0m ", messageIn.data[6]);
                            }
                        else
                            {
                            pc.printf("\033[1;32m%02X\033[0m ", messageIn.data[6]);
                            }
                        if (expected10 != messageIn.data[7] and checklaterbytes >= 1)
                            {
                            //pc.printf("Data 7 of %d does NOT match %d.\r\n", messageIn.data[7], expected10);
                            pc.printf("\033[1;31m%02X\033[0m ", messageIn.data[7]);
                            }
                        else
                            {
                            pc.printf("\033[1;32m%02X\033[0m ", messageIn.data[7]);
                            }
                        if (messageinisneeded == 1)
                            {
                            //pc.printf("\r\n(Aftersentoutmessage)");
                            pc.printf("\r\n");//Add a return and a new line after the 'Sent out' message is finished if it's not spam mode.
                            }
                        }
                    if (itsamatch == 0)
                        {
                        mismatchfailsthistest++;
                        if (aspamisgoing == 1)
                            {
                            //pc.printf("\r\n(ToseparateMRWfromDNM)"); //Having a new line here separated 'message received was:...' from 'Does NOT match...' too much.
                            }
                        if (messageinisneeded == 1)
                            {
                            pc.printf("Does NOT match      : %03X %01X %02X %02X %02X %02X %02X %02X %02X %02X\r", expected1, expected2, expected3, expected4, expected5, expected6, expected7, expected8, expected9, expected10);
                            //pc.printf("Check later bytes is %d.\r\n", checklaterbytes);
                            if (messageinisneeded == 1 and aspamisgoing == 0)
                                {
                                pc.printf("\n\n");
                                }
                            if (messageinisneeded == 1 and aspamisgoing == 1)
                                {
                                pc.printf("\n\n");
                                }
                            }
                        failsthistest++; //Add 1 to failsthistest to mark the fail
                        expectationwasfulfilled = 0;
                        expectationresolved = 1;
                        }
                    if (itsamatch == 1)
                        {
                        expectationwasfulfilled = 1;
                        expectationresolved = 1;
                        matchesthistest++;
                        //If it's a match, write out a 'Matches expectation...' message
                        if (messageinisneeded == 1)
                            {
                            pc.printf("Matches expectation : %03X %01X %02X %02X %02X %02X %02X %02X %02X %02X\r", expected1, expected2, expected3, expected4, expected5, expected6, expected7, expected8, expected9, expected10);
                            if (aspamisgoing == 0)
                                {
                                pc.printf("\n\n");
                                }
                            }
                        }
                    }
                if (idspamon == 1)
                    {
                    idscheckedcount++;
                    idlistincrementer++; //Only add 1 to the idlist incrementer at the end so the first ID it sends is '000'.
                    }
                if (customentry == 1)
                    {
                    pc.printf("Enter CAN ID to send: ");
                    }
                }
            //If speed-spam is on, spam a CAN message as fast as possible.
            }
        if (speedspamison == 1)
            {
            //sendCAN();
            CanBus.write(messageOut1);
            spamcount++;
            //pc.printf("\rSent %d '%03X %01X %02X %02X %02X %02X %02X %02X %02X %02X' messages...", spamcount, messageOut1.id, messageOut1.len, messageOut1.data[0], messageOut1.data[1], messageOut1.data[2], messageOut1.data[3], messageOut1.data[4], messageOut1.data[5], messageOut1.data[6], messageOut1.data[7]);
            //Pressing 'Esc' switches off speed spam mode
            wait(0.00001);
            }
        }
    }