Skip to content

Commit

Permalink
Add test for timer
Browse files Browse the repository at this point in the history
  • Loading branch information
malcx95 committed Jan 18, 2024
1 parent 0fdbcf5 commit 97a3119
Show file tree
Hide file tree
Showing 5 changed files with 207 additions and 23 deletions.
106 changes: 106 additions & 0 deletions core/testutil/testdevice.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#pragma once

#include "../../device.h"
#include "../backlight/color.h"
#include "../../common/constants.h"

namespace testutil
{

/**
* Device implementation for testing purposes.
*/
class TestDeviceBase : public Device
{
public:
virtual void sleep_millis(const int) { }
virtual void sleep_micros(const int) { }
virtual void gpio_setup(const uint8_t, const PinMode) { }
virtual void gpio_write(const uint8_t, const PinState) { }
virtual PinState gpio_read(const uint8_t) { return {}; }

virtual void set_keyboard_key1(const uint8_t) { }
virtual void set_keyboard_key2(const uint8_t) { }
virtual void set_keyboard_key3(const uint8_t) { }
virtual void set_keyboard_key4(const uint8_t) { }
virtual void set_keyboard_key5(const uint8_t) { }
virtual void set_keyboard_key6(const uint8_t) { }
virtual void set_keyboard_modifier(const uint16_t) { }
virtual void set_keyboard_media(const uint16_t) { }
virtual void keyboard_send() { }

// TODO may need more work
// virtual bool sd_read(const char* filename, char* buffer, const uint32_t buffer_size) { }

virtual uint16_t get_keyboard_leds() { return 0; }

virtual void serial_begin(const uint32_t) { }
virtual void serial_print(const char*) { }

virtual void serial_print(uint8_t) { }
virtual void serial_print(uint16_t) { }
virtual void serial_print(uint32_t) { }
virtual void serial_print(int8_t) { }
virtual void serial_print(int16_t) { }
virtual void serial_print(int32_t) { }

virtual void serial_println(const char*) { }
virtual void serial_println(uint8_t) { }
virtual void serial_println(uint16_t) { }
virtual void serial_println(uint32_t) { }
virtual void serial_println(int8_t) { }
virtual void serial_println(int16_t) { }
virtual void serial_println(int32_t) { }

virtual void start_timer() { }
virtual uint32_t get_timer_micros() { return 0; }

/**
* Milliseconds since the device was started.
*/
virtual uint32_t millis() const { return 0; }

virtual void set_led(uint16_t, uint8_t, uint8_t, uint8_t) { }
virtual void update_leds() { }

};

class TestTimerLEDDevice : public TestDeviceBase
{
public:
TestTimerLEDDevice()
{
for (int i = 0; i < common::constants::TOTAL_NUM_LEDS; ++i)
{
led_colors_r[i] = 0;
led_colors_g[i] = 0;
led_colors_b[i] = 0;
}
}

uint32_t current_millis = 0;
uint32_t millis() const override
{
return current_millis;
}

bool leds_updated = true;
void update_leds() override
{
leds_updated = true;
}

uint8_t led_colors_r[common::constants::TOTAL_NUM_LEDS];
uint8_t led_colors_g[common::constants::TOTAL_NUM_LEDS];
uint8_t led_colors_b[common::constants::TOTAL_NUM_LEDS];

void set_led(uint16_t index, uint8_t r, uint8_t g, uint8_t b) override
{
led_colors_r[index] = r;
led_colors_g[index] = g;
led_colors_b[index] = b;
}
};

}

13 changes: 13 additions & 0 deletions core/testutil/testutilities.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once

#include <cmath>

namespace testutil
{

inline bool float_equals(float f1, float f2, float delta = 0.00001)
{
return fabs(f1 - f2) < delta;
}

}
49 changes: 49 additions & 0 deletions core/util/test/test_timer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include <catch_amalgamated.hpp>
#include "../../testutil/testdevice.h"
#include "../../testutil/testutilities.h"
#include "../timer.h"


TEST_CASE("Test timer", "[Timer]")
{
testutil::TestTimerLEDDevice device;

core::util::Timer timer;
timer.duration = 100;

// the timer should be able to restart without reinitialization
for (int i = 0; i < 2; ++i)
{
const uint32_t time_offset = i * 200;
device.current_millis = 0 + time_offset;
timer.start(device);

timer.update(device);
// no time has passed yet
CHECK(timer.remaining_time() == 100);
CHECK(testutil::float_equals(timer.progress(), 0.0f));
CHECK(!timer.is_finished());

device.current_millis = 50 + time_offset;

timer.update(device);
// 50 milliseconds have passed
CHECK(timer.remaining_time() == 50);
CHECK(testutil::float_equals(timer.progress(), 0.5f));
CHECK(!timer.is_finished());

device.current_millis = 99 + time_offset;

timer.update(device);
CHECK(timer.remaining_time() == 1);
CHECK(testutil::float_equals(timer.progress(), 0.99f));
CHECK(!timer.is_finished());

device.current_millis = 101 + time_offset;

timer.update(device);
CHECK(timer.remaining_time() == 0);
CHECK(testutil::float_equals(timer.progress(), 1.0f));
CHECK(timer.is_finished());
}
}
24 changes: 7 additions & 17 deletions core/util/timer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,51 +4,41 @@
namespace core::util
{

void Timer::start(Device& device)
void Timer::start(const Device& device)
{
running = true;
remainingTime = duration;
time_remaining = duration;
start_time = device.millis();
}

void Timer::stop()
{
running = false;
}

void Timer::update(Device& device)
void Timer::update(const Device& device)
{
if (running)
{
uint32_t current_time = device.millis();
uint32_t elapsed = current_time - start_time;
remainingTime = duration - elapsed;
time_remaining = duration - elapsed;
if (elapsed >= duration)
{
running = false;
remainingTime = 0;
time_remaining = 0;
}
}
}

bool Timer::is_running() const
{
return running;
}

bool Timer::is_finished() const
{
return !running;
}

uint32_t Timer::remaining_time() const
{
return remainingTime;
return time_remaining;
}

float Timer::progress() const
{
return 1.0f - static_cast<float>(remainingTime) / static_cast<float>(duration);
return 1.0f - static_cast<float>(time_remaining) / static_cast<float>(duration);
}

}
38 changes: 32 additions & 6 deletions core/util/timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,46 @@
namespace core::util
{

// Note: the reason we cannot have Device& as a field in the Timer struct is because
// we would need to have a non-default constructor, which causes a problem for LEDState,
// which is in an array so it cannot be initialized using a non-default constructor.

struct Timer
{
void start(Device& device);
void stop();
void update(Device& device);
bool is_running() const;
/**
* Starts the timer, resetting the timer remaining to the duration.
*/
void start(const Device& device);

/**
* Updates the internal state of the timer, run this before reading the timer state.
*/
void update(const Device& device);

/**
* Whether the timer duration has elapsed.
*/
bool is_finished() const;

/**
* The number of milliseconds remaining.
*/
uint32_t remaining_time() const;

/**
* The percentage amount of time between the start and the duration.
* 0 means just started, 1 means finished.
*/
float progress() const;

/**
* The timer duration in milliseconds.
*/
uint32_t duration;

private:
uint32_t start_time;
uint32_t remainingTime;
uint32_t start_time = 0;
uint32_t time_remaining = 0;
bool running = false;
};

Expand Down

0 comments on commit 97a3119

Please sign in to comment.