A timing app designed to run on my Odroid-GO
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

272 lines
6.8 KiB

#include <esp_log.h>
#include <esp_timer.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <string.h>
#include "macros.h"
#include "odroid/audio.h"
#include "odroid/battery.h"
#include "odroid/display.h"
#include "odroid/input.h"
#include "odroid/sdcard.h"
#include "odroid/sleep.h"
#include "text.h"
#define ArraySize(array) sizeof((array)) / sizeof((array)[0])
static bool drawBatteryVoltage = false;
static bool drawBatteryPercent = true;
static bool drawTimeSinceBoot = false;
static bool drawFrameRate = true;
/* static bool printInput = true; */
static bool printInput = true;
static bool enableLowFrameRate = true;
static int64_t autoSleepModeMicroseconds = 10 * 1000000;
static int64_t lightSleepMicroseconds = 30 * 1000000;
static const char* LOG_TAG = "Main";
static uint16_t gFramebuffer[LCD_WIDTH * LCD_HEIGHT];
/* static const uint16_t lightPalette[4] = */
/* { */
/* 0xFFFF, */
/* 0x55AD, */
/* 0xAA52, */
/* 0x0000, */
/* }; */
static const uint16_t darkPalette[4] = {
0x0000,
0xAA52,
0x55AD,
0xFFFF,
};
static const uint16_t* palette = darkPalette;
void updateBatteryIndicator()
{
float batteryPercentage = Odroid_ReadBatteryLevelPercentage();
if (batteryPercentage < 15.f)
Odroid_EnableBatteryLight();
else
Odroid_DisableBatteryLight();
}
void app_main(void)
{
Odroid_InitializeInput();
Odroid_InitializeDisplay();
// Does not work for me yet
/* Odroid_InitializeSdcard(); */
Odroid_InitializeBatteryReader();
/* Odroid_InitializeAudio(); */
ESP_LOGI(LOG_TAG, "Odroid initialization complete - entering main loop");
/* uint8_t frameIndex = 0; */
/* char snapFilename[20]; */
bool timerRunning = false;
int64_t timerStartMicroSecs = 0;
// Includes timings before pause, not current timing
int64_t timerTotalMicroSecsPrePause = 0;
int64_t lastFrameTimeMicroSecs = esp_timer_get_time();
int64_t timeSinceLastInputMicroSecs = esp_timer_get_time();
Odroid_Input lastFrameInput = {0};
typedef enum AppState
{
Sleeping,
Awake_WaitingForWakeButtonRelease,
Awake,
} AppState;
AppState state = Awake;
while (true)
{
if (state == Awake || state == Awake_WaitingForWakeButtonRelease)
{
memset(gFramebuffer, palette[0], 320 * 240 * 2);
updateBatteryIndicator();
int64_t currentTimeMicroSecs = esp_timer_get_time();
Odroid_Input input = Odroid_PollInput();
bool hasInputsThisFrame = Odroid_HasAnyInput(&input);
if (hasInputsThisFrame)
timeSinceLastInputMicroSecs = esp_timer_get_time();
if (printInput)
Odroid_PrintInputState(&input);
if (state == Awake_WaitingForWakeButtonRelease)
{
if (!hasInputsThisFrame)
{
state = Awake;
lastFrameInput = input;
}
}
bool buttonPressedForSleepMode = false;
// Only take inputs after wake button released
if (state == Awake)
{
if (input.a && !lastFrameInput.a)
{
printf("Toggle timer\n");
timerRunning = !timerRunning;
if (timerRunning)
timerStartMicroSecs = currentTimeMicroSecs;
else
timerTotalMicroSecsPrePause += currentTimeMicroSecs - timerStartMicroSecs;
}
if (input.start && !lastFrameInput.start)
{
printf("Reset timer\n");
timerRunning = false;
timerTotalMicroSecsPrePause = 0;
}
buttonPressedForSleepMode = (lastFrameInput.b && !input.b);
}
bool noInputsSleepMode =
currentTimeMicroSecs - timeSinceLastInputMicroSecs > autoSleepModeMicroseconds;
if (noInputsSleepMode || buttonPressedForSleepMode)
{
state = Sleeping;
printf("Entering sleep reason: ");
if (noInputsSleepMode)
printf("No inputs in %lld seconds ", autoSleepModeMicroseconds / 1000000);
if (buttonPressedForSleepMode)
printf("Sleep button pressed ");
printf("\n");
}
// Timer
{
char string[18];
int64_t currentTimeMicroSecs = esp_timer_get_time();
float timerSeconds = timerRunning ?
((timerTotalMicroSecsPrePause +
(currentTimeMicroSecs - timerStartMicroSecs)) /
1000000.f) :
timerTotalMicroSecsPrePause / 1000000.f;
snprintf(string, ArraySize(string), "%d:%.2d", (int)timerSeconds / 60,
(int)timerSeconds % 60);
DrawText(gFramebuffer, string, ArraySize(string), 3, 5, palette[3]);
if (!timerRunning)
{
snprintf(string, ArraySize(string), "Paused");
DrawText(gFramebuffer, string, ArraySize(string), 3, 6, palette[3]);
}
}
// Battery
if (drawBatteryPercent)
{
char string[10];
snprintf(string, ArraySize(string), "B: %.0f", Odroid_ReadBatteryLevelPercentage());
DrawText(gFramebuffer, string, ArraySize(string), 0, 0, palette[3]);
}
if (drawBatteryVoltage)
{
char string[10];
snprintf(string, ArraySize(string), "B: %03d", Odroid_ReadBatteryLevel());
DrawText(gFramebuffer, string, ArraySize(string), 0, 3, palette[3]);
}
// Time since boot
if (drawTimeSinceBoot)
{
char string[10];
int64_t timeSinceBoot = esp_timer_get_time();
snprintf(string, ArraySize(string), "%lld", timeSinceBoot);
DrawText(gFramebuffer, string, ArraySize(string), 0, 1, palette[3]);
}
// Frame time
if (drawFrameRate)
{
char string[10];
int64_t currentTimeMicroSecs = esp_timer_get_time();
int64_t frameTimeMicroSecs = currentTimeMicroSecs - lastFrameTimeMicroSecs;
snprintf(string, ArraySize(string), "%.2f HZ", 1000000.f / frameTimeMicroSecs);
DrawText(gFramebuffer, string, ArraySize(string), 12, 0, palette[3]);
lastFrameTimeMicroSecs = currentTimeMicroSecs;
}
Odroid_DrawFrame(gFramebuffer);
// Just high enough that button presses feel responsive
if (enableLowFrameRate)
vTaskDelay(5);
lastFrameInput = input;
// Save screenshots for making gifs
/* if (input.menu) */
/* { */
/* snprintf(snapFilename, 20, "/sdcard/frame%02d", frameIndex); */
/* ESP_LOGI(LOG_TAG, "Writing snapshot to %s", snapFilename); */
/* FILE* snapFile = fopen(snapFilename, "wb"); */
/* assert(snapFile); */
/* fwrite(gFramebuffer, 1, LCD_WIDTH * LCD_HEIGHT * sizeof(gFramebuffer[0]),
* snapFile); */
/* fclose(snapFile); */
/* ++frameIndex; */
/* } */
}
if (state == Sleeping)
{
// Enter sleep
{
// TODO: Tell LCD driver to enter sleep
Odroid_BacklightDeinit();
}
// Try to save battery while still listening to inputs
// This loop is exited only if wake button is pressed
while (!Odroid_EnterLightSleep(lightSleepMicroseconds))
{
updateBatteryIndicator();
}
// Exit sleep
{
// Count this input so sleep isn't immediately entered
timeSinceLastInputMicroSecs = esp_timer_get_time();
Odroid_BacklightInit();
state = Awake_WaitingForWakeButtonRelease;
}
}
}
// Should never get here
esp_restart();
}