Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,9 +1,87 @@
#include "Training.h"

// uint8_t 8 bit-unsigned integer
uint8_t outputArray[3];
uint8_t validData; // Set bits 0, 1, 2 if the input array elements were valid
uint8_t isMotorDataValid(uint8_t isMotorOn, uint8_t motorVelocity);

/**
NOTE: I decided that if the motors do not have matching ON/OFF status or do not have matching velocity*, both motor inputs will be flagged as wrong (it's hard to know which motor is "right" when they are not in sync).

* Velocity will be compared in its vector form. i.e. v1 = v2 if and only if they are equal in magnitude and direction.
*/
void trainingTask(uint8_t* data)
{
// MOTORS
// Check equality in motor ON/OFF status
uint8_t isMotorOneOn = 0b00000001 & data[0];
uint8_t isMotorTwoOn = 0b00000001 & data[1];

// Check equality in velocity (magnitude and direction)
uint8_t motorOneVelocity = (0b11111110 & data[0]) >> 1;
uint8_t motorTwoVelocity = (0b11111110 & data[1]) >> 1;

// Check motors are in sync
uint8_t isSynced = (isMotorOneOn == isMotorTwoOn) && (motorOneVelocity == motorTwoVelocity);

// If the motors are in sync only need to check if one motor is valid since they must be equal!
// Set validData bits accordingly
// If motors are valid, copy data onto outputArray
if(isSynced && isMotorDataValid(isMotorOneOn, motorOneVelocity)){
validData = 0b11000000;
outputArray[0] = data[0];
outputArray[1] = data[1];
} else {
validData = 0b00000000;
}

// LIGHTS
// Check exactly one of the headlight statuses is on
uint8_t isHeadlightOff = (0b10000000 & data[2]) >> 7;
uint8_t isHeadlightLow = (0b01000000 & data[2]) >> 6;
uint8_t isHeadlightHigh = (0b00100000 & data[2]) >> 5;
uint8_t isHeadlightValid = isHeadlightOff ^ isHeadlightLow ^ isHeadlightHigh;

// In order to check signal lights we needs to know if hazards are on and then determine the right behaviour.
uint8_t isHazardOn = (0b00000100 & data[2]) >> 2;
uint8_t isRightSignalOn = (0b00010000 & data[2]) >> 4;
uint8_t isLeftSignalOn = (0b00001000 & data[2]) >> 3;
uint8_t isSignalValid;

// When hazard light is on, the signals must both be in the same state to denote blinking.
// When hazards are not on, signals may not be on at the same time
isSignalValid = isHazardOn ? !(isRightSignalOn ^ isLeftSignalOn) : !(isRightSignalOn && isLeftSignalOn);

// Copy data onto outputArray if lights are valid
// Set bit 2 of validData accordingly
if (isHeadlightValid && isSignalValid)
{
validData = 0b00100000 | validData;
outputArray[2] = data[2];
} else {
validData = 0b11011111 & validData;
}

}

/** @brief Function that takes in motor ON/OFF status and returns 1 if data
* is valid and 0 if data is not valid. This function only looks at the motor as a
* standalone unit and aasumes that it is synced with the other motor.
*
* @param[in] isMotorOn 8 bit integer with value 0000000 or 0000001
* @param[in] motorVelocity 8 bit integer representing the velocity of the motor.
*/
uint8_t isMotorDataValid(uint8_t isMotorOn, uint8_t motorVelocity) {

if(isMotorOn){
// If motor is on, the sign of the velocity needs to match the direction
// Forward: 1, Positive: 0
uint8_t isForward = (0b10000000 & motorVelocity) >> 6;
uint8_t velocitySign = (0b00000001 & motorVelocity);
return (isForward != velocitySign) ? 1 : 0;
} else {
// Since motor is off, input is valid iff velocity is 0
return (!motorVelocity) ? 1 : 0;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,85 @@

extern uint8_t outputArray[3];
extern uint8_t validData;
void resetOutput();

void runTrainingTests()
{
// Run all the tests here using RUN_TEST()
RUN_TEST(test_EverythingValid);
RUN_TEST(test_EverythingInvalid);
RUN_TEST(test_OnlyLightsInvalid);
RUN_TEST(test_OnlyMotorsInvalid);
}

void test_EverythingValid()
{

resetOutput();
uint8_t data[3] = {0b01001011,0b01001011, 0b00110000};
uint8_t expected[3] = {0b01001011,0b01001011, 0b00110000};
trainingTask(data);
TEST_ASSERT_EQUAL_UINT8(0b11100000, validData);
TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, outputArray, 3);
}

void test_EverythingInvalid()
{

resetOutput();
uint8_t data[3] = {0b11011011, 0b10010000, 0b11111000};
uint8_t expected[3] = {0,0,0};
trainingTask(data);
TEST_ASSERT_EQUAL_UINT8(0b00000000, validData);
TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, outputArray, 3);
}

void test_OnlyLightsInvalid()
{
uint8_t expected[3] = {0b10010111,0b10010111,0};

// Case 1: Headlights are in two states
resetOutput();
uint8_t data1[3] = {0b10010111,0b10010111,0b11000000};
trainingTask(data1);
TEST_ASSERT_EQUAL_UINT8(0b11000000, validData);
TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, outputArray, 3);

// Case 2: Hazards off, but both signals are on
resetOutput();
uint8_t data2[3] = {0b10010111,0b10010111,0b10011000};
trainingTask(data2);
TEST_ASSERT_EQUAL_UINT8(0b11000000, validData);
TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, outputArray, 3);

// Case 3: Hazards on, but signals not flashing
resetOutput();
uint8_t data3[3] = {0b10010111,0b10010111,0b10010100};
trainingTask(data3);
TEST_ASSERT_EQUAL_UINT8(0b11000000, validData);
TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, outputArray, 3);

}

void test_OnlyMotorsInvalid()
{
uint8_t expected[3] = {0,0,0b01000000};
// Case 1: Motors not in sync
resetOutput();
uint8_t data1[3] = {0b11100111, 0b01001001, 0b01000000};
trainingTask(data1);
TEST_ASSERT_EQUAL_UINT8(0b00100000, validData);
TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, outputArray, 3);

// Case 2: Motors in sync, but turned off with non-zero velocity
resetOutput();
uint8_t data2[3] = {0b11000000, 0b11000000, 0b01000000};
trainingTask(data2);
TEST_ASSERT_EQUAL_UINT8(0b00100000, validData);
TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, outputArray, 3);
}

void resetOutput() {
for (int i = 0; i < 3; i++)
{
outputArray[i] = 0;
}
validData = 0;
}