aboutsummaryrefslogtreecommitdiff
path: root/test.c
diff options
context:
space:
mode:
authorDavid Phillips <david@yeah.nah.nz>2019-03-02 23:25:29 +1300
committerDavid Phillips <david@yeah.nah.nz>2019-03-02 23:25:29 +1300
commit1fddc966d25022ba3e198ab7100e500c4ce1450d (patch)
tree1cc76628f2a061d6ec236762a648711cd0f787dd /test.c
parent4982b556540b403a1411436ed398cc523653d82f (diff)
downloadclock-disp-1fddc966d25022ba3e198ab7100e500c4ce1450d.tar.xz
Rename from test to clock-disp
Diffstat (limited to 'test.c')
-rw-r--r--test.c397
1 files changed, 0 insertions, 397 deletions
diff --git a/test.c b/test.c
deleted file mode 100644
index c8d8c74..0000000
--- a/test.c
+++ /dev/null
@@ -1,397 +0,0 @@
-#include <SDL.h>
-#include <SDL_ttf.h>
-#include <stdio.h>
-#include <time.h>
-#include <pthread.h>
-#include <unistd.h>
-#include <semaphore.h>
-
-enum ALIGN_MODE {
- ALIGN_MODE_LEFT,
- ALIGN_MODE_CENTRE,
- ALIGN_MODE_RIGHT,
-};
-
-#define WINDOW_TITLE "Clock Display"
-#define SCREEN_WIDTH 800
-#define SCREEN_HEIGHT 480
-
-#define TIME_X 0
-#define TIME_Y -50
-
-#define NO_LOCK_Y 150
-
-#define DATE_1_X 20
-#define DATE_1_Y 295
-#define DATE_2_X 20
-#define DATE_2_Y 350
-
-#define SECONDS_X SCREEN_WIDTH - 80
-#define SECONDS_Y SCREEN_HEIGHT - 55
-
-#define NTP_INFO_X 240
-#define NTP_INFO_Y SCREEN_HEIGHT - 55
-#define SAT_INFO_X 20
-#define SAT_INFO_Y NTP_INFO_Y
-
-#define SUN_INFO_X SCREEN_WIDTH -20
-#define SUN_INFO_1_Y DATE_1_Y
-#define SUN_INFO_2_Y DATE_2_Y
-
-/* Common colours used */
-#define COLOUR_WHITE ((SDL_Color){255,255,255,255})
-#define COLOUR_YELLOW ((SDL_Color){255,191, 32,255})
-#define COLOUR_40GRAY ((SDL_Color){100,100,100,255})
-
-static sem_t data_lock;
-struct clock_data {
- int is_unread;
- char sunrise_time[8];
- char sunset_time[8];
- int sat_seen;
- int sat_used;
- int leap_second;
- int offset;
- char offset_units[8];
- int no_gps_lock;
-};
-
-static volatile struct clock_data shared_data;
-
-/**
- * Publish a struct clock_data to the volatile global clock data object.
- * Caller MUST already hold data_lock
- */
-void publish_clock_data(struct clock_data *l)
-{
- char *d = (char*)&shared_data;
- char *s = (char*)l;
- size_t i = 0;
- for (i = 0; i < sizeof(struct clock_data); i++) {
- d[i] = s[i];
- }
- shared_data.is_unread = 1;
-}
-
-/**
- * Copy the published struct clock_data to a non-volatile clock data object.
- * Caller MUST already hold data_lock
- */
-void get_clock_data(struct clock_data *l)
-{
- char *d = (char*)l;
- char *s = (char*)&shared_data;
- size_t i = 0;
- for (i = 0; i < sizeof(struct clock_data); i++) {
- d[i] = s[i];
- }
-}
-
-/**
- * Read clock's statistics from files and push them into shared data area for
- * display thread to pick up
- */
-void *read_stats(void* unused)
-{
- char buffer[32];
- char *next = buffer;
- FILE *f = NULL;
- struct clock_data l;
- memset(&l, 0, sizeof(l));
-
- while (1) {
- /* Read sunrise, sunset */
- if (f = fopen("/tmp/stats-sun", "r")) {
- if (fgets(buffer, sizeof(buffer), f)) {
- /* format is %d/%d\n, first is used sats, second is total seen */
- if (next = strchr(buffer, ',')) {
- *(next++) = '\0';
- next[strcspn(next, "\n\r\t")] = '\0';
- strncpy(l.sunrise_time, buffer, sizeof(l.sunrise_time));
- strncpy(l.sunset_time, next, sizeof(l.sunset_time));
- }
- }
- fclose(f);
- }
-
- /* Read satellite stats */
- if (f = fopen("/tmp/stats-sats", "r")) {
- if (fgets(buffer, sizeof(buffer), f)) {
- /* format is %d,%d\n, first is used sats, second is total seen */
- if (next = strchr(buffer, '/')) {
- *(next++) = '\0';
- l.sat_used = strtod(buffer, NULL);
- l.sat_seen = strtod(next, NULL);
- }
- }
- fclose(f);
- }
-
- /* read leap second status file - also helps determine lock */
- if (f = fopen("/tmp/stats-leap", "r")) {
- if (fgets(buffer, sizeof(buffer), f)) {
- buffer[strcspn(buffer, "\n\r\t")] = '\0';
- l.no_gps_lock = !strcmp(buffer, "Not synchronised");
- l.leap_second = strcmp(buffer, "Normal");
- }
- fclose(f);
- }
-
- if (f = fopen("/tmp/stats-clock", "r")) {
- if (fgets(buffer, sizeof(buffer), f)) {
- const char *units[] = { "s", "ms", "µs", "ns", "ps", "fs" };
- int i = 0;
- double offset = fabs(strtod(buffer, NULL));
- while (offset < 1 && i < sizeof(units)/sizeof(units[0]) - 1) {
- i++;
- offset *= 1000;
- }
- l.offset = offset;
- strncpy(l.offset_units, units[i], sizeof(l.offset_units));
- }
- fclose(f);
- }
- sem_wait(&data_lock);
- publish_clock_data(&l);
- sem_post(&data_lock);
- sleep(5);
- }
-}
-
-const char *get_th_suffix(unsigned int day)
-{
- if (11 <= day && day <= 19) {
- return "th";
- } else {
- switch (day % 10) {
- case 1: return "st";
- case 2: return "nd";
- case 3: return "rd";
- default: /* 0, 4-9 */
- return "th";
- }
- }
-}
-
-TTF_Font *loadFont(const char *file, int size)
-{
- TTF_Font *font = TTF_OpenFont(file, size);
- if (!font) {
- printf("Error: TTF_OpenFont: %s\n", TTF_GetError());
- return NULL;
- }
- return font;
-}
-
-void renderTexture(SDL_Texture *tex, SDL_Renderer *ren, int x, int y){
- //Setup the destination rectangle to be at the position we want
- SDL_Rect dst;
- dst.x = x;
- dst.y = y;
- //Query the texture to get its width and height to use
- SDL_QueryTexture(tex, NULL, NULL, &dst.w, &dst.h);
- SDL_RenderCopy(ren, tex, NULL, &dst);
-}
-
-
-SDL_Texture* renderText(const char *message, TTF_Font *font, SDL_Color color, SDL_Renderer *renderer)
-{
- //We need to first render to a surface as that's what TTF_RenderText
- //returns, then load that surface into a texture
- SDL_Surface *surf = TTF_RenderUTF8_Blended(font, message, color);
- if (!surf){
- printf("Error in TTF_RenderUTF8_Blended\n");
- return NULL;
- }
- SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surf);
- if (!texture){
- printf("Error in SDL_CreateTextureFromSurface\n");
- }
- //Clean up the surface and font
- SDL_FreeSurface(surf);
- return texture;
-}
-
-int drawText(const char *text, TTF_Font *font, SDL_Color color, SDL_Renderer *renderer, int x, int y, enum ALIGN_MODE mode) {
- /* FIXME does this need better error detection */
- int text_w;
- SDL_Texture *image;
- image = renderText(text, font, color, renderer);
- SDL_QueryTexture(image, NULL, NULL, &text_w, NULL);
-
- if (mode == ALIGN_MODE_CENTRE) {
- x = SCREEN_WIDTH / 2 - text_w / 2;
- } else if (mode == ALIGN_MODE_RIGHT) {
- x -= text_w;
- }
- renderTexture(image, renderer, x, y);
- SDL_DestroyTexture(image);
- return x + (mode == ALIGN_MODE_RIGHT? 0 : 1) * text_w;
-}
-
-int main(void)
-{
- struct clock_data l;
-
- /* initial unread indicator value */
- shared_data.is_unread = 0;
-
- strncpy(l.sunrise_time, "??:??", sizeof(l.sunrise_time));
- strncpy(l.sunset_time, "??:??", sizeof(l.sunset_time));
- l.sat_seen = 0;
- l.sat_used = 0;
- l.leap_second = 0;
- l.offset = 0;
- strncpy(l.offset_units, "?", sizeof(l.offset_units));
- l.no_gps_lock = 1;
-
- if (sem_init(&data_lock, 0, 1)) {
- perror("sem_init");
- return 1;
- }
-
- int stop = 0;
- SDL_Event e;
- SDL_Window *window;
-
- SDL_Init(SDL_INIT_VIDEO);
- TTF_Init();
-
- TTF_Font *mainTimeFont = loadFont("/usr/share/fonts/TTF/RobotoMono-Regular.ttf", 325);
- TTF_Font *noLockFont = loadFont("/usr/share/fonts/TTF/Roboto-Regular.ttf", 130);
- TTF_Font *secondsFont = loadFont("/usr/share/fonts/TTF/RobotoMono-Regular.ttf", 30);
-
- TTF_Font *dateFont = loadFont("/usr/share/fonts/TTF/Roboto-Regular.ttf", 50);
- TTF_Font *dateSymbolFont = loadFont("/usr/share/fonts/TTF/Symbola.ttf", 50);
-
- TTF_Font *ntpInfoFont= loadFont("/usr/share/fonts/TTF/Roboto-Regular.ttf", 30);
- TTF_Font *ntpSymbolFont = loadFont("/usr/share/fonts/TTF/Symbola.ttf", 30);
- if ( !ntpSymbolFont
- || !dateSymbolFont
- || !mainTimeFont
- || !dateFont
- || !secondsFont
- || !ntpInfoFont) {
- return 1;
- }
-
- /* launch pthread */
- pthread_t thread;
- if (pthread_create(&thread, NULL, read_stats, NULL) != 0) {
- perror("pthread_create");
- return 1;
- }
-
- window = SDL_CreateWindow(WINDOW_TITLE, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_OPENGL);
- if (!window) {
- printf("Could not create window: %s\n", SDL_GetError());
- return 1;
- }
-
- SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
- if (!renderer) {
- SDL_DestroyWindow(window);
- printf("SDL_CreateRenderer Error\n");
- SDL_Quit();
- return 1;
- }
-
- while (!stop)
- {
- while (SDL_PollEvent(&e)){
- if ( e.type == SDL_QUIT
- || e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_q) {
- stop = 1;
- }
- }
- char text[64];
- time_t t;
- struct tm *time_s;
-
-
- SDL_Texture *image;
- int text_w;
-
- SDL_RenderClear(renderer);
-
- t = time(NULL);
- if ((time_s = localtime(&t)) == NULL) {
- /* FIXME error */
- continue;
- }
-
- int next_x = 0;
-
- sem_wait(&data_lock);
- if (shared_data.is_unread) {
- get_clock_data(&l);
- shared_data.is_unread = 0;
- }
- sem_post(&data_lock);
-
- if (l.sat_seen == 0 || l.sat_used == 0 || l.no_gps_lock) {
- drawText("No GPS Lock", noLockFont, COLOUR_WHITE, renderer, 0, NO_LOCK_Y, ALIGN_MODE_CENTRE);
- } else {
- /* Have GPS lock, go for it */
- /**/
- strftime(text, sizeof(text), "%H%M", time_s);
- drawText(text, mainTimeFont, COLOUR_WHITE, renderer, TIME_X, TIME_Y, ALIGN_MODE_CENTRE);
- /**/
-
- /********************/
- /* Draws a date string, normally like:
- * Monday the 25th
- * February, 2019
- */
- strftime(text, sizeof(text), "%A", time_s);
- next_x = drawText(text, dateFont, COLOUR_WHITE, renderer, DATE_1_X, DATE_1_Y, ALIGN_MODE_LEFT);
-
- next_x = drawText(" the ", dateFont, COLOUR_40GRAY, renderer, next_x, DATE_1_Y, ALIGN_MODE_LEFT);
-
- snprintf(text, sizeof(text), "%d%s", time_s->tm_mday, get_th_suffix(time_s->tm_mday));
- next_x = drawText(text, dateFont, COLOUR_WHITE, renderer, next_x, DATE_1_Y, ALIGN_MODE_LEFT);
- next_x = drawText(".", dateFont, COLOUR_40GRAY, renderer, next_x, DATE_1_Y, ALIGN_MODE_LEFT);
-
- strftime(text, sizeof(text), "%B", time_s);
- next_x = drawText(text, dateFont, COLOUR_WHITE, renderer, DATE_2_X, DATE_2_Y, ALIGN_MODE_LEFT);
-
- next_x = drawText(", ", dateFont, COLOUR_40GRAY, renderer, next_x, DATE_2_Y, ALIGN_MODE_LEFT);
-
- strftime(text, sizeof(text), "%Y", time_s);
- next_x = drawText(text, dateFont, COLOUR_WHITE, renderer, next_x, DATE_2_Y, ALIGN_MODE_LEFT);
- /********************/
-
- /**/
- strftime(text, sizeof(text), ":%S", time_s);
- next_x = drawText(text, secondsFont, COLOUR_WHITE, renderer, SECONDS_X, SECONDS_Y, ALIGN_MODE_LEFT);
- /**/
-
- /**/
- next_x = drawText("⏰ ", ntpSymbolFont, COLOUR_40GRAY, renderer, NTP_INFO_X, NTP_INFO_Y, ALIGN_MODE_LEFT);
- snprintf(text, sizeof(text), " RMS %d %s%s ", l.offset, l.offset_units,
- l.leap_second ? ", Leap second coming!" : "");
- next_x = drawText(text, ntpInfoFont, COLOUR_40GRAY, renderer, next_x, NTP_INFO_Y, ALIGN_MODE_LEFT);
- /**/
-
- /**/
- next_x = drawText(l.sunrise_time, dateFont, COLOUR_WHITE, renderer, SUN_INFO_X, SUN_INFO_1_Y, ALIGN_MODE_RIGHT);
- next_x = drawText("☀⬆", dateSymbolFont, COLOUR_YELLOW, renderer, next_x, SUN_INFO_1_Y, ALIGN_MODE_RIGHT);
- next_x = drawText(l.sunset_time, dateFont, COLOUR_WHITE, renderer, SUN_INFO_X, SUN_INFO_2_Y, ALIGN_MODE_RIGHT);
- next_x = drawText("☀⬇", dateSymbolFont, COLOUR_YELLOW, renderer, next_x, SUN_INFO_2_Y, ALIGN_MODE_RIGHT);
- // next_x = drawText("⭡05:45 ↓20:13", dateFont, COLOUR_WHITE, renderer, SUN_INFO_X, SUN_INFO_Y);
- /**/
- }
- /**/
- next_x = drawText("🛰 ", ntpSymbolFont, COLOUR_40GRAY, renderer, SAT_INFO_X, SAT_INFO_Y, ALIGN_MODE_LEFT);
- snprintf(text, sizeof(text), "%d (%d used)", l.sat_seen, l.sat_used);
- next_x = drawText(text, ntpInfoFont, COLOUR_40GRAY, renderer, next_x, NTP_INFO_Y, ALIGN_MODE_LEFT);
- /**/
- SDL_RenderPresent(renderer);
- SDL_Delay(100);
- }
-
- SDL_DestroyWindow(window);
- SDL_Quit();
- return 0;
-}
-