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.
 
 
 
 

274 lines
7.7 KiB

#include "odroid/audio.h"
#include "odroid/battery.h"
#include "odroid/display.h"
#include "odroid/input.h"
#include "odroid/sdcard.h"
#include "macros.h"
#include "text.h"
#include <esp_log.h>
#include <esp_timer.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <string.h>
#define ArraySize(array) sizeof((array)) / sizeof((array)[0])
static const char* LOG_TAG = "Main";
static uint16_t gFramebuffer[LCD_WIDTH * LCD_HEIGHT];
static bool drawBattery = true;
static bool drawTimeSinceBoot = true;
static bool drawFrameRate = true;
/* static const uint16_t lightPalette[4] = */
/* { */
/* 0xFFFF, */
/* 0x55AD, */
/* 0xAA52, */
/* 0x0000, */
/* }; */
static const uint16_t palette[4] =
{
0x0000,
0xAA52,
0x55AD,
0xFFFF,
};
static const uint8_t tiles[][16*16] =
{
// White
{
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
},
// Light Grey
{
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
},
// Dark Grey
{
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,2,2,2,2,2,2,2,2,2,2,2,2,0,0,
0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
0,0,2,2,2,2,2,2,2,2,2,2,2,2,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
},
// Black
{
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,3,3,3,3,3,3,3,3,3,3,3,3,0,0,
0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,
0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,
0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,
0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,
0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,
0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,
0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,
0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,
0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,
0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,
0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,
0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,
0,0,3,3,3,3,3,3,3,3,3,3,3,3,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
},
};
static int tileBuffer[15][40] =
{
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0},
{0, 0, 3, 0, 0, 0, 3, 3, 3, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0},
{2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
};
void DrawTile(int index, int x, int y)
{
int startX = x * 16;
int startY = y * 16;
for (int row = 0; row < 16; ++row)
{
for (int col = 0; col < 16; ++col)
{
uint8_t paletteIndex = tiles[index][row * 16 + col];
int screenY = startY + row;
int screenX = startX + col;
uint16_t color = palette[paletteIndex];
gFramebuffer[screenY * LCD_WIDTH + screenX] = color;
}
}
}
void app_main(void)
{
Odroid_InitializeInput();
Odroid_InitializeDisplay();
/* Odroid_InitializeSdcard(); */
Odroid_InitializeBatteryReader();
/* Odroid_InitializeAudio(); */
ESP_LOGI(LOG_TAG, "Odroid initialization complete - entering main loop");
uint8_t frameIndex = 0;
char snapFilename[20];
int xLeft = 0;
int64_t lastFrameTimeMicroSecs = esp_timer_get_time();
for (;;)
{
memset(gFramebuffer, palette[0], 320*240*2);
Odroid_Input input = Odroid_PollInput();
// Movement
/* if (input.left) */
/* { */
/* xLeft -= 1; */
/* if (xLeft < 0) */
/* { */
/* xLeft = 39; */
/* } */
/* } */
/* else if (input.right) */
/* { */
/* xLeft += 1; */
/* if (xLeft > 39) */
/* { */
/* xLeft = 0; */
/* } */
/* } */
// Tile drawing
/* for (int tileY = 0; tileY < 15; ++tileY) */
/* { */
/* for (int tileX = xLeft; tileX < xLeft + 20; ++tileX) */
/* { */
/* int tile = tileX % 40; */
/* int tileIndex = tileBuffer[tileY][tile]; */
/* DrawTile(tileIndex, tileX - xLeft, tileY); */
/* } */
/* } */
// Battery
if (drawBattery)
{
char string[10];
snprintf(string, ArraySize(string), "B: %02d", Odroid_ReadBatteryLevel());
/* snprintf(string, ArraySize(string), "B: %02d", Odroid_ReadBatteryLevel()); */
DrawText(gFramebuffer, string, ArraySize(string), 0, 0, 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;
}
// 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; */
/* } */
Odroid_DrawFrame(gFramebuffer);
}
// Should never get here
esp_restart();
}