]> code.bitgloo.com Git - clyne/stm-game.git/commitdiff
move source to folder; openocd.sh programs directly
authorClyne Sullivan <clyne@bitgloo.com>
Sun, 5 Jun 2022 22:36:34 +0000 (18:36 -0400)
committerClyne Sullivan <clyne@bitgloo.com>
Sun, 5 Jun 2022 22:36:34 +0000 (18:36 -0400)
25 files changed:
.gitignore
2048.c [deleted file]
2048.h [deleted file]
Makefile
buttons.c [deleted file]
buttons.h [deleted file]
dogs.c [deleted file]
dogs.h [deleted file]
flapbird.c [deleted file]
flapbird.h [deleted file]
main.c [deleted file]
openocd.sh
osal.c [deleted file]
osal.h [deleted file]
source/2048.c [new file with mode: 0644]
source/2048.h [new file with mode: 0644]
source/buttons.c [new file with mode: 0644]
source/buttons.h [new file with mode: 0644]
source/dogs.c [new file with mode: 0644]
source/dogs.h [new file with mode: 0644]
source/flapbird.c [new file with mode: 0644]
source/flapbird.h [new file with mode: 0644]
source/main.c [new file with mode: 0644]
source/osal.c [new file with mode: 0644]
source/osal.h [new file with mode: 0644]

index 9d7552698dc9fd9ec2cfc430f2885bb05564c02d..9401e391d91674833d7139fa26a693e2a0708d54 100644 (file)
@@ -1,3 +1,3 @@
 ChibiOS_*/
 build
-.dep
+.*
diff --git a/2048.c b/2048.c
deleted file mode 100644 (file)
index ce73844..0000000
--- a/2048.c
+++ /dev/null
@@ -1,104 +0,0 @@
-#include "buttons.h"
-#include "dogs.h"
-
-static int values[16];
-
-void g2048_init()
-{
-    for (int i = 0; i < 16; i++)
-        values[i] = 0;
-}
-
-int g2048_loop()
-{
-    if ((button_state & BUTTON_JOYUP) == BUTTON_JOYUP) {
-        for (int x = 0; x < 3; x++) {
-            for (int y = 0; y < 3; y++) {
-
-                if (values[4 * y + x] != 0)
-                    continue;
-            }
-        }
-
-        for (int y = 3; y > 0; y--) {
-            for (int x = 0; x < 4; x++) {
-                if (values[4 * y + x] != 0) {
-                    if (values[4 * (y - 1) + x] == 0)
-                        values[4 * (y - 1) + x] = values[4 * y + x], values[4 * y + x] = 0;
-                    else if (values[4 * (y - 1) + x] == values[4 * y + x])
-                        values[4 * (y - 1) + x]++, values[4 * y + x] = 0;
-                }
-            }
-        }
-
-        for (int i = 15; i >= 0; i--) {
-            if (values[i] == 0) {
-                values[i] = 1;
-                break;
-            }
-        }
-    } else if ((button_state & BUTTON_JOYDOWN) == BUTTON_JOYDOWN) {
-        for (int y = 0; y < 3; y++) {
-            for (int x = 0; x < 4; x++) {
-                if (values[4 * y + x] != 0) {
-                    if (values[4 * (y + 1) + x] == 0)
-                        values[4 * (y + 1) + x] = values[4 * y + x], values[4 * y + x] = 0;
-                    else if (values[4 * (y + 1) + x] == values[4 * y + x])
-                        values[4 * (y + 1) + x]++, values[4 * y + x] = 0;
-                }
-            }
-        }
-
-        for (int i = 15; i >= 0; i--) {
-            if (values[i] == 0) {
-                values[i] = 1;
-                break;
-            }
-        }
-    } else if ((button_state & BUTTON_JOYLEFT) == BUTTON_JOYLEFT) {
-        for (int x = 3; x > 0; x--) {
-            for (int y = 0; y < 4; y++) {
-                if (values[4 * y + x] != 0) {
-                    if (values[4 * y + x - 1] == 0)
-                        values[4 * y + x - 1] = values[4 * y + x], values[4 * y + x] = 0;
-                    else if (values[4 * y + x - 1] == values[4 * y + x])
-                        values[4 * y + x - 1]++, values[4 * y + x] = 0;
-                }
-            }
-        }
-
-        for (int i = 15; i >= 0; i--) {
-            if (values[i] == 0) {
-                values[i] = 1;
-                break;
-            }
-        }
-    } else if ((button_state & BUTTON_JOYRIGHT) == BUTTON_JOYRIGHT) {
-        for (int x = 0; x < 3; x++) {
-            for (int y = 0; y < 4; y++) {
-                if (values[4 * y + x] != 0) {
-                    if (values[4 * y + x + 1] == 0)
-                        values[4 * y + x + 1] = values[4 * y + x], values[4 * y + x] = 0;
-                    else if (values[4 * y + x + 1] == values[4 * y + x])
-                        values[4 * y + x + 1]++, values[4 * y + x] = 0;
-                }
-            }
-        }
-
-        for (int i = 15; i >= 0; i--) {
-            if (values[i] == 0) {
-                values[i] = 1;
-                break;
-            }
-        }
-    }
-
-    dogs_clear();
-    for (int i = 0; i < 16; i++) {
-        if (values[i] != 0)
-            draw_number(31 + 10 * (i % 4), 12 + 10 * (3 - (i / 4)), values[i]);
-    }
-    dogs_flush();
-
-    return 500;
-}
diff --git a/2048.h b/2048.h
deleted file mode 100644 (file)
index b8bdf14..0000000
--- a/2048.h
+++ /dev/null
@@ -1,3 +0,0 @@
-void g2048_init();
-int g2048_loop();
-
index 050356ddd991d580d5e322d063d5bca86d94da19..3fedc917c5d9347508bfdb547625f63eae6e88bc 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -102,33 +102,17 @@ include $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC/mk/startup_stm32l0xx.m
 include $(CHIBIOS)/os/hal/hal.mk\r
 include $(CHIBIOS)/os/hal/ports/STM32/STM32L0xx/platform.mk\r
 include $(CHIBIOS)/os/hal/boards/ST_NUCLEO32_L011K4/board.mk\r
-#include $(CHIBIOS)/os/hal/osal/os-less/ARMCMx/osal.mk\r
-#include $(CHIBIOS)/os/hal/osal/rt-nil/osal.mk\r
-# RTOS files (optional).\r
-#include $(CHIBIOS)/os/nil/nil.mk\r
-#include $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/port_v6m.mk\r
 # Auto-build files in ./source recursively.\r
-#include $(CHIBIOS)/tools/mk/autobuild.mk\r
-# Other files (optional).\r
-#include $(CHIBIOS)/test/lib/test.mk\r
-#include $(CHIBIOS)/test/nil/nil_test.mk\r
-#include $(CHIBIOS)/test/oslib/oslib_test.mk\r
+include $(CHIBIOS)/tools/mk/autobuild.mk\r
 \r
 # Define linker script file here\r
-#LDSCRIPT= $(STARTUPLD)/STM32L011x4.ld\r
 LDSCRIPT= ./STM32L011x4.ld\r
 \r
 # C sources that can be compiled in ARM or THUMB mode depending on the global\r
 # setting.\r
 CSRC = $(ALLCSRC) \\r
        $(TESTSRC) \\r
-          $(CHIBIOS)/os/hal/osal/lib/osal_vt.c \\r
-          2048.c \\r
-          buttons.c \\r
-          dogs.c \\r
-          flapbird.c \\r
-       main.c \\r
-          osal.c\r
+       $(CHIBIOS)/os/hal/osal/lib/osal_vt.c\r
 \r
 # C++ sources that can be compiled in ARM or THUMB mode depending on the global\r
 # setting.\r
diff --git a/buttons.c b/buttons.c
deleted file mode 100644 (file)
index 45ea7bd..0000000
--- a/buttons.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * buttons.c - Provides ability to read button state.
- * Copyright (C) 2020  Clyne Sullivan
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * See the GNU General Public License for more details.
- */
-
-#include "buttons.h"
-#include "hal.h"
-
-unsigned char button_state = 0;
-
-static void buttonStateHandler(void *arg)
-{
-    int pad = (unsigned int)arg & 0xFF;
-    int bit = 1 << ((unsigned int)arg >> 8);
-
-    if (!palReadPad(GPIOA, pad)) {
-        if ((button_state & bit) != bit)
-            button_state |= bit;
-    } else {
-        if ((button_state & bit) == bit)
-            button_state &= ~(bit);
-    }
-}
-
-void buttons_init()
-{
-    palSetPadMode(GPIOA, 0, PAL_MODE_INPUT_PULLUP);   // Joy A (UL)
-    palSetPadMode(GPIOA, 1, PAL_MODE_INPUT_PULLUP);   // Joy B (UR)
-    palSetPadMode(GPIOA, 2, PAL_MODE_INPUT_PULLUP);   // Joy C (DR)
-    palSetPadMode(GPIOA, 3, PAL_MODE_INPUT_PULLUP);   // Joy D (DL)
-    palSetPadMode(GPIOA, 6, PAL_MODE_INPUT_PULLUP);   // Joy button
-    palSetPadMode(GPIOA, 7, PAL_MODE_INPUT_PULLUP);   // Button 1
-    palSetPadMode(GPIOA, 9, PAL_MODE_INPUT_PULLUP);   // Button 2
-    palSetPadMode(GPIOA, 10, PAL_MODE_INPUT_PULLUP);  // Button 3
-    palEnablePadEvent(GPIOA, 0, PAL_EVENT_MODE_BOTH_EDGES);
-    palEnablePadEvent(GPIOA, 1, PAL_EVENT_MODE_BOTH_EDGES);
-    palEnablePadEvent(GPIOA, 2, PAL_EVENT_MODE_BOTH_EDGES);
-    palEnablePadEvent(GPIOA, 3, PAL_EVENT_MODE_BOTH_EDGES);
-    palEnablePadEvent(GPIOA, 6, PAL_EVENT_MODE_BOTH_EDGES);
-    palEnablePadEvent(GPIOA, 7, PAL_EVENT_MODE_BOTH_EDGES);
-    palEnablePadEvent(GPIOA, 9, PAL_EVENT_MODE_BOTH_EDGES);
-    palEnablePadEvent(GPIOA, 10, PAL_EVENT_MODE_BOTH_EDGES);
-    palSetPadCallback(GPIOA, 0, buttonStateHandler, (void *)0x0700);
-    palSetPadCallback(GPIOA, 1, buttonStateHandler, (void *)0x0601);
-    palSetPadCallback(GPIOA, 2, buttonStateHandler, (void *)0x0502);
-    palSetPadCallback(GPIOA, 3, buttonStateHandler, (void *)0x0403);
-    palSetPadCallback(GPIOA, 6, buttonStateHandler, (void *)0x0306);
-    palSetPadCallback(GPIOA, 7, buttonStateHandler, (void *)0x0207);
-    palSetPadCallback(GPIOA, 9, buttonStateHandler, (void *)0x0109);
-    palSetPadCallback(GPIOA, 10, buttonStateHandler, (void *)0x000A);
-}
-
diff --git a/buttons.h b/buttons.h
deleted file mode 100644 (file)
index ba7e02d..0000000
--- a/buttons.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * buttons.h - Provides ability to read button state.
- * Copyright (C) 2020  Clyne Sullivan
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * See the GNU General Public License for more details.
- */
-
-#ifndef BUTTONS_H_
-#define BUTTONS_H_
-
-#define BUTTON_JOYUL (1 << 7)
-#define BUTTON_JOYUR (1 << 6)
-#define BUTTON_JOYDR (1 << 5)
-#define BUTTON_JOYDL (1 << 4)
-#define BUTTON_JOY   (1 << 3)
-#define BUTTON_1     (1 << 2)
-#define BUTTON_2     (1 << 1)
-#define BUTTON_3     (1 << 0)
-
-#define BUTTON_JOYUP    (BUTTON_JOYUL | BUTTON_JOYUR)
-#define BUTTON_JOYDOWN  (BUTTON_JOYDL | BUTTON_JOYDR)
-#define BUTTON_JOYLEFT  (BUTTON_JOYUL | BUTTON_JOYDL)
-#define BUTTON_JOYRIGHT (BUTTON_JOYUR | BUTTON_JOYDR)
-
-extern unsigned char button_state;
-
-void buttons_init();
-
-#endif // BUTTONS_H_
-
diff --git a/dogs.c b/dogs.c
deleted file mode 100644 (file)
index 101339f..0000000
--- a/dogs.c
+++ /dev/null
@@ -1,356 +0,0 @@
-/**
- * dogs.c - Interface for drawing to the EADOGS102N-6 display.
- * Copyright (C) 2020  Clyne Sullivan
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * See the GNU General Public License for more details.
- */
-
-//#include "ch.h"
-#include "dogs.h"
-#include "hal.h"
-
-#define SET_DATA palSetPad(GPIOC, 15)
-#define SET_CMD  palClearPad(GPIOC, 15)
-#define CS_HIGH  palSetPad(GPIOA, 4)
-#define CS_LOW   palClearPad(GPIOA, 4)
-unsigned char dogs_buffer[DISP_WIDTH * DISP_HEIGHT / 8];
-
-//static volatile bool dogs_spi_done = false;
-
-#define spi_send(data, len) spiSend(&SPID1, len, data)
-//static void spi_send(unsigned char *data, unsigned int len)
-//{
-    //dogs_spi_done = false;
-    //spiStartSend(&SPID1, len, data);
-    //while (!dogs_spi_done)
-    //    asm("wfi");
-
-    //for (; len > 0; --len)
-    //    spiPolledExchange(&SPID1, *data++);
-//}
-
-static void dogs_init_display();
-//static void dogs_spi_callback(SPIDriver *spid)
-//{
-//    if (spiIsBufferComplete(spid))
-//        dogs_spi_done = true;
-//}
-
-void dogs_init()
-{
-    // SPI
-    palSetPadMode(GPIOB, 1, PAL_MODE_ALTERNATE(1));     // MOSI
-    palSetPadMode(GPIOA, 5, PAL_MODE_ALTERNATE(0));     // CLK
-    palSetPadMode(GPIOA, 4, PAL_MODE_OUTPUT_PUSHPULL);  // nCS
-    palSetPadMode(GPIOC, 14, PAL_MODE_OUTPUT_PUSHPULL); // nRST
-    palSetPadMode(GPIOC, 15, PAL_MODE_OUTPUT_PUSHPULL); // CD
-
-    palSetPad(GPIOA, 4);
-    palSetPad(GPIOC, 14);
-    palClearPad(GPIOC, 15);
-
-    static const SPIConfig spicfg = {
-        false,
-        NULL /*dogs_spi_callback*/,
-        0, // cr1
-        0
-    };
-    spiStart(&SPID1, &spicfg);
-
-    dogs_init_display();
-    dogs_clear();
-    dogs_flush();
-}
-
-void dogs_write_cmd(unsigned char byte)
-{
-    spi_send(&byte, 1);
-}
-
-void dogs_set_column(unsigned int col)
-{
-    dogs_write_cmd(0x10 | ((col >> 4) & 0xF));
-    dogs_write_cmd(0x00 | (col & 0xF));
-}
-void dogs_set_power(unsigned int bits)
-{
-    dogs_write_cmd(0x28 | (bits & 0x7));
-}
-void dogs_set_scroll_line(unsigned int startline)
-{
-    dogs_write_cmd(0x40 | (startline & 0x3F));
-}
-void dogs_set_page(unsigned int page)
-{
-    dogs_write_cmd(0xB0 | (page & 0xF));
-}
-void dogs_set_vlcd_ratio(unsigned int ratio)
-{
-    dogs_write_cmd(0x20 | (ratio & 0x7));
-}
-void dogs_set_contrast(unsigned int value)
-{
-    dogs_write_cmd(0x81);
-    dogs_write_cmd(0x00 | (value & 0x3F));
-}
-void dogs_set_pixelson(bool on)
-{
-    dogs_write_cmd(on ? 0xA5 : 0xA4);
-}
-void dogs_set_invert(bool invert)
-{
-    dogs_write_cmd(invert ? 0xA7 : 0xA6);
-}
-void dogs_set_sleep(bool sleep)
-{
-    dogs_write_cmd(sleep ? 0xAE : 0xAF);
-}
-void dogs_set_segdir(bool normal)
-{
-    dogs_write_cmd(normal ? 0xA0 : 0xA1);
-}
-void dogs_set_comdir(bool normal)
-{
-    dogs_write_cmd(normal ? 0xC0 : 0xC8);
-}
-void dogs_reset()
-{
-    dogs_write_cmd(0xE2);
-}
-void dogs_set_bias(bool higher)
-{
-    dogs_write_cmd(higher ? 0xA2 : 0xA3);
-}
-void dogs_set_advanced(unsigned int bits)
-{
-    dogs_write_cmd(0xFA);
-    dogs_write_cmd(0x10 | bits);
-}
-
-void dogs_init_display()
-{
-    SET_CMD;
-    CS_LOW;
-    dogs_reset();
-    CS_HIGH;
-
-       unsigned long int reset_sleep = (STM32_SYSCLK / 1000) * 100;
-       while (reset_sleep != 0) {
-               asm("nop; nop; nop; nop; nop");
-               reset_sleep -= 8;
-       }
-
-    CS_LOW;
-    dogs_set_scroll_line(0);
-    dogs_set_segdir(true);
-    dogs_set_comdir(false);
-    dogs_set_pixelson(false);
-    dogs_set_invert(false);
-    dogs_set_bias(true);
-    dogs_set_power(0x07);
-    dogs_set_vlcd_ratio(7);
-    dogs_set_contrast(12);
-    dogs_set_advanced(0x83);
-    dogs_set_sleep(false);
-    CS_HIGH;
-}
-
-void dogs_clear()
-{
-    uint32_t *ptr = (uint32_t *)dogs_buffer;
-    unsigned int count = sizeof(dogs_buffer) / sizeof(uint32_t) / 12;
-
-    for (; count; --count) {
-        *ptr++ = 0;
-        *ptr++ = 0;
-        *ptr++ = 0;
-        *ptr++ = 0;
-        *ptr++ = 0;
-        *ptr++ = 0;
-        *ptr++ = 0;
-        *ptr++ = 0;
-        *ptr++ = 0;
-        *ptr++ = 0;
-        *ptr++ = 0;
-        *ptr++ = 0;
-    }
-}
-
-void dogs_flush()
-{
-    unsigned char *ptr = dogs_buffer;
-    CS_LOW;
-    for (int page = 0; page < 8; ++page) {
-        SET_CMD;
-        dogs_set_page(page);
-        dogs_set_column(30);
-
-        SET_DATA;
-        spi_send(ptr, 102);
-        ptr += 102;
-    }
-    CS_HIGH;
-}
-
-void draw_pixel(int x, int y, bool state)
-{
-    if (x < 0 || y < 0 || x >= DISP_WIDTH || y >= DISP_HEIGHT)
-        return;
-    y = DISP_HEIGHT - 1 - y;
-    if (state)
-        dogs_buffer[y / 8 * DISP_WIDTH + x] |= (1 << (y % 8));
-    else
-        dogs_buffer[y / 8 * DISP_WIDTH + x] &= ~(1 << (y % 8));
-}
-
-void draw_rect(int x, int y, int w, int h)
-{
-    for (int i = 0; i < w; i++) {
-        for (int j = 0; j < h; j++)
-            draw_pixel(x + i, y + j, true);
-    }
-}
-
-void draw_bitmap(int x, int y, const unsigned char *buffer)
-{
-    // Prepare source information
-    const unsigned char *src = buffer;
-    const int width = *src++;
-    const int height = *src++;
-    int sbit = 0;
-
-    for (int j = 0; j < height; j++) {
-        for (int i = 0; i < width; i++) {
-            draw_pixel(x + i, y + j, *src & (1 << sbit));
-            if (++sbit == 8) {
-                sbit = 0;
-                ++src;
-            }
-        }
-    }
-}
-
-static const unsigned char draw_number_bitmaps[10][10] = {
-    { 8, 8, // '0'
-        0b00011000,
-        0b00100100,
-        0b01000010,
-        0b01000010,
-        0b01000010,
-        0b01000010,
-        0b00100100,
-        0b00011000,
-    },
-    { 8, 8, // '1'
-        0b01111100,
-        0b00010000,
-        0b00010000,
-        0b00010000,
-        0b00010000,
-        0b00010000,
-        0b00010100,
-        0b00011000,
-    },
-    { 8, 8, // '2'
-        0b01111110,
-        0b00001000,
-        0b00010000,
-        0b00100000,
-        0b01000000,
-        0b01000010,
-        0b00100100,
-        0b00011000,
-    },
-    { 8, 8, // '3'
-        0b00011100,
-        0b00100010,
-        0b01000000,
-        0b00100000,
-        0b00111100,
-        0b01000000,
-        0b00100010,
-        0b00011100,
-    },
-    { 8, 8, // '4'
-        0b00100000,
-        0b00100000,
-        0b00100000,
-        0b00111110,
-        0b00100100,
-        0b00101000,
-        0b00110000,
-        0b00100000,
-    },
-    { 8, 8, // '5'
-        0b00011100,
-        0b00100010,
-        0b01000000,
-        0b01000000,
-        0b00100000,
-        0b00011110,
-        0b00000010,
-        0b01111110,
-    },
-    { 8, 8, // '6'
-        0b00011000,
-        0b00100100,
-        0b01000010,
-        0b01000110,
-        0b00111010,
-        0b00000010,
-        0b00000100,
-        0b00111000,
-    },
-    { 8, 8, // '7'
-        0b00001000,
-        0b00001000,
-        0b00001000,
-        0b00001000,
-        0b00010000,
-        0b00100000,
-        0b01000000,
-        0b01111110,
-    },
-    { 8, 8, // '8'
-        0b00011000,
-        0b00100100,
-        0b01000010,
-        0b00100100,
-        0b00111100,
-        0b01000010,
-        0b00100100,
-        0b00011000,
-    },
-    { 8, 8, // '9'
-        0b00011100,
-        0b00100010,
-        0b01000000,
-        0b01111000,
-        0b01000100,
-        0b01000010,
-        0b00100100,
-        0b00011000,
-    },
-};
-
-void draw_number(int x, int y, int number)
-{
-    if (number < 0)
-        number = -number;
-    int tmp = number;
-    int count;
-    for (count = 0; tmp; count++)
-        tmp /= 10;
-    if (count == 0)
-        count = 1;
-    x += count * 8;
-    do {
-        x -= 8;
-        draw_bitmap(x, y, draw_number_bitmaps[number % 10]);
-    } while (number /= 10);
-}
-
diff --git a/dogs.h b/dogs.h
deleted file mode 100644 (file)
index 8af24fd..0000000
--- a/dogs.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * dogs.h - Interface for drawing to the EADOGS102N-6 display.
- * Copyright (C) 2020  Clyne Sullivan
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * See the GNU General Public License for more details.
- */
-
-#ifndef DOGS_H_
-#define DOGS_H_
-
-#include <stdbool.h>
-
-#define DISP_WIDTH  102
-#define DISP_HEIGHT 64
-
-extern unsigned char dogs_buffer[DISP_WIDTH * DISP_HEIGHT / 8];
-
-void dogs_init();
-void dogs_clear();
-void dogs_flush();
-void dogs_set_sleep(bool sleep);
-
-void draw_pixel(int x, int y, bool state);
-void draw_rect(int x, int y, int w, int h);
-void draw_bitmap(int x, int y, const unsigned char *buffer);
-void draw_number(int x, int y, int number);
-
-#endif // DOGS_H_
-
diff --git a/flapbird.c b/flapbird.c
deleted file mode 100644 (file)
index f2dd2cf..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-#include "buttons.h"
-#include "dogs.h"
-
-static const unsigned char bird[] = {
-    8, 8,
-    0b00111100,
-    0b01100110,
-    0b01000010,
-    0b01111110,
-    0b01100110,
-    0b01000010,
-    0b11000000,
-    0b11000000,
-};
-
-static int score;
-static int t1x, t1o;
-static int t2x, t2o;
-static int py;
-static int vy;
-static int counter;
-
-void flapbird_init()
-{
-    score = 0;
-    t1x = DISP_WIDTH / 2, t1o = 15;
-    t2x = DISP_WIDTH, t2o = 49;
-    py = DISP_HEIGHT / 2 - 4;
-    vy = 0;
-    counter = 0;
-}
-
-int flapbird_loop()
-{
-    // Player logic
-    if (py > 0) {
-        py += vy;
-        if (vy > -3)
-            vy--;
-    } else {
-        if (py < 0)
-            py = 0;
-        if (score > 0)
-            score = 0;
-    }
-
-    if (button_state & BUTTON_2) {
-        vy = 5;
-        if (py <= 0)
-            py = 1;
-    }
-
-    // Rendering
-    dogs_clear();
-
-    draw_rect(t1x, 0, 4, t1o - 10);
-    draw_rect(t1x, t1o + 10, 4, DISP_HEIGHT - t1o + 10);
-    draw_rect(t2x, 0, 4, t2o - 10);
-    draw_rect(t2x, t2o + 10, 4, DISP_HEIGHT - t2o + 10);
-    draw_bitmap(4, py, bird);
-
-    draw_number(DISP_WIDTH - 25, DISP_HEIGHT - 8, score);
-    dogs_flush();
-
-    // Game logic
-    if (t1x == 4)
-        score = (py + 2 > t1o - 10 && py + 6 < t1o + 10) ? score + 1 : 0;
-    if (t2x == 4)
-        score = (py + 2 > t2o - 10 && py + 6 < t2o + 10) ? score + 1 : 0;
-
-    t1x -= 2;
-    if (t1x <= -5)
-        t1x = DISP_WIDTH;
-    t2x -= 2;
-    if (t2x <= -5)
-        t2x = DISP_WIDTH;
-
-    return 100;
-}
-
diff --git a/flapbird.h b/flapbird.h
deleted file mode 100644 (file)
index 7ab4199..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef FLAPBIRD_H_
-#define FLAPBIRD_H_
-
-void flapbird_init();
-int flapbird_loop();
-
-#endif // FLAPBIRD_H_
-
diff --git a/main.c b/main.c
deleted file mode 100644 (file)
index 1ef13bf..0000000
--- a/main.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/**
- * main.c - Firmware entry point and main loop for game or testing.
- * Copyright (C) 2020  Clyne Sullivan
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * See the GNU General Public License for more details.
- */
-
-#include "buttons.h"
-#include "dogs.h"
-#include "hal.h"
-
-//#include "2048.h"
-#include "flapbird.h"
-
-/*
- * Progress:
- *  - Serial through LPUART1 works (38400 baud, takes over swdio pins)
- *  - Display comm. over SPI, can clear screen
- *  - Can read buttons through PAL (through interrupts now)
- *  - Use ADC to read Vintref, print to screen in mV
- *  - Sleep mode via WFI, saves ~0.5mA (we're running around 1.1mA)
- *  - Run at 512kHz, only use HSI for ADC: 360uA (jumpy)
- *  - Drop to 1.2V Vcore (range 3), enable low-V detector: 375uA (steady) (440uA at 1MHz)
- *  - Run at 4MHz, drop to low-power run/sleep @ 64kHz for idle: 375uA (also lowered contrast)
- *  - Sleep display for 'pause': ~240uA
- *
- *  - Use RTC for delay, Stop mode when idle: 348uA
- *
- *  - Flappy bird is going, 2048 next
- */
-
-static int readVddmv();
-
-static void alarm_callback(RTCDriver *rtcp, rtcevent_t event)
-{
-    (void)rtcp;
-    (void)event;
-
-    static bool sleep = false;
-
-       bool sleep_button = (button_state & BUTTON_1) != 0;
-    if (sleep && !sleep_button)
-               return;
-
-    RCC->ICSCR |= 6 << RCC_ICSCR_MSIRANGE_Pos;
-    dogs_set_sleep(false);
-
-    if (sleep_button) {
-        sleep ^= true;
-        if (sleep) {
-            draw_number(DISP_WIDTH - 33, 0,
-                        !(PWR->CSR & PWR_CSR_PVDO) ? readVddmv() : 1);
-            dogs_flush();
-        }
-    }
-
-    if (!sleep)
-        flapbird_loop();
-
-    dogs_set_sleep(true);
-}
-
-int main(void)
-{
-    halInit();
-    //chSysInit();
-    buttons_init();
-
-    dogs_init();
-    flapbird_init();
-
-    static const RTCWakeup wakeupcfg = {
-        (0 << 16) | // wucksel (37k /16 = ~2k)
-        200         // wut (hope for 10Hz)
-    };
-    rtcSTM32SetPeriodicWakeup(&RTCD1, &wakeupcfg);
-    rtcSetCallback(&RTCD1, alarm_callback);
-
-    RCC->CR &= ~RCC_CR_HSION;
-    PWR->CR |= PWR_CR_LPSDSR | PWR_CR_ULP;
-    PWR->CR |= PWR_CR_LPRUN;
-    SCB->SCR = 6;
-    //FLASH->ACR |= FLASH_ACR_SLEEP_PD;
-
-    // Below code for serial -- note that it cuts off debugging, and MUST be used in a thread
-    //chThdSleepMilliseconds(2000);
-    //palSetPadMode(GPIOA, 13, PAL_MODE_ALTERNATE(6));
-    //palSetPadMode(GPIOA, 14, PAL_MODE_ALTERNATE(6));
-    //sdStart(&LPSD1, NULL);
-    //chnWrite(&LPSD1, (const uint8_t *)"Hello World!\r\n", 14);
-
-    /* This is now the idle thread loop, you may perform here a low priority
-       task but YOU MUST NEVER TRY TO SLEEP OR WAIT in this loop. Note that
-       this tasks runs at the lowest priority level so any instruction added
-       here will be executed after all other tasks have been started. */
-    while (1)
-        asm("wfe");
-}
-
-void HardFault_Handler()
-{
-    while (1);
-}
-
-static volatile bool adc_is_complete = false;
-static void adc_callback(ADCDriver *adcd)
-{
-    (void)adcd;
-    adc_is_complete = true;
-}
-
-static const ADCConfig adccfg = {
-    .dummy = 0
-};
-
-static const ADCConversionGroup adcgrpcfg = {
-  .circular     = false,
-  .num_channels = 1,
-  .end_cb       = adc_callback,
-  .error_cb     = NULL,
-  .cfgr1        = ADC_CFGR1_RES_12BIT,     /* CFGR1 */
-  .cfgr2        = 0,                       /* CFGR2 */
-  .tr           = ADC_TR(0, 0),            /* TR */
-  .smpr         = ADC_SMPR_SMP_1P5,        /* SMPR */
-  .chselr       = ADC_CHSELR_CHSEL17       /* CHSELR */
-};
-
-int readVddmv()
-{
-    adcsample_t reading = 0;
-
-    RCC->CR |= RCC_CR_HSION;
-    while (!(RCC->CR & RCC_CR_HSIRDY));
-
-    adcStart(&ADCD1, &adccfg);
-    adcSTM32EnableVREF(&ADCD1);
-    adcStartConversion(&ADCD1, &adcgrpcfg, &reading, 1);
-    while (!adc_is_complete);
-    adcStopConversion(&ADCD1);
-    adcSTM32DisableVREF(&ADCD1);
-    adcStop(&ADCD1);
-
-    RCC->CR &= ~RCC_CR_HSION;
-
-    return 3000 * /* CAL */ *((adcsample_t *)0x1FF80078) / reading;
-}
index 90d40529a6a2c06bb4972409d729d8a603fec48f..1ce7e72b09984232cfb136cb6f9d828ef4a6afa0 100755 (executable)
@@ -1 +1 @@
-sudo openocd -f /usr/local/share/openocd/scripts/interface/stlink-v2.cfg -f /usr/local/share/openocd/scripts/target/stm32l0.cfg
+openocd -f /usr/local/share/openocd/scripts/interface/stlink-v2.cfg -f /usr/local/share/openocd/scripts/target/stm32l0.cfg -c "init; program build/ch.hex verify reset exit"
diff --git a/osal.c b/osal.c
deleted file mode 100644 (file)
index 5c62069..0000000
--- a/osal.c
+++ /dev/null
@@ -1,467 +0,0 @@
-/*\r
-    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio\r
-\r
-    Licensed under the Apache License, Version 2.0 (the "License");\r
-    you may not use this file except in compliance with the License.\r
-    You may obtain a copy of the License at\r
-\r
-        http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-    Unless required by applicable law or agreed to in writing, software\r
-    distributed under the License is distributed on an "AS IS" BASIS,\r
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-    See the License for the specific language governing permissions and\r
-    limitations under the License.\r
-*/\r
-\r
-/**\r
- * @file    osal.c\r
- * @brief   OSAL module code.\r
- *\r
- * @addtogroup OSAL\r
- * @{\r
- */\r
-\r
-#include "osal.h"\r
-#include "osal_vt.h"\r
-\r
-/*===========================================================================*/\r
-/* Module local definitions.                                                 */\r
-/*===========================================================================*/\r
-\r
-/*===========================================================================*/\r
-/* Module exported variables.                                                */\r
-/*===========================================================================*/\r
-\r
-/**\r
- * @brief   Pointer to a halt error message.\r
- * @note    The message is meant to be retrieved by the debugger after the\r
- *          system halt caused by an unexpected error.\r
- */\r
-const char *osal_halt_msg;\r
-\r
-/*===========================================================================*/\r
-/* Module local types.                                                       */\r
-/*===========================================================================*/\r
-\r
-/*===========================================================================*/\r
-/* Module local variables.                                                   */\r
-/*===========================================================================*/\r
-\r
-/*===========================================================================*/\r
-/* Module local functions.                                                   */\r
-/*===========================================================================*/\r
-\r
-static void callback_timeout(void *p) {\r
-  osalSysLockFromISR();\r
-  osalThreadResumeI((thread_reference_t *)p, MSG_TIMEOUT);\r
-  osalSysUnlockFromISR();\r
-}\r
-\r
-/*===========================================================================*/\r
-/* Module exported functions.                                                */\r
-/*===========================================================================*/\r
-\r
-/**\r
- * @brief   OSAL module initialization.\r
- *\r
- * @api\r
- */\r
-void osalInit(void) {\r
-\r
-  vtInit();\r
-\r
-  OSAL_INIT_HOOK();\r
-}\r
-\r
-/**\r
- * @brief   System halt with error message.\r
- *\r
- * @param[in] reason    the halt message pointer\r
- *\r
- * @api\r
- */\r
-#if !defined(__DOXYGEN__)\r
-__attribute__((weak, noreturn))\r
-#endif\r
-void osalSysHalt(const char *reason) {\r
-\r
-  osalSysDisable();\r
-  osal_halt_msg = reason;\r
-  while (true) {\r
-  }\r
-}\r
-\r
-/**\r
- * @brief   Polled delay.\r
- * @note    The real delay is always few cycles in excess of the specified\r
- *          value.\r
- *\r
- * @param[in] cycles    number of cycles\r
- *\r
- * @xclass\r
- */\r
-void osalSysPolledDelayX(rtcnt_t cycles) {\r
-\r
-  (void)cycles;\r
-}\r
-\r
-/**\r
- * @brief   System timer handler.\r
- * @details The handler is used for scheduling and Virtual Timers management.\r
- *\r
- * @iclass\r
- */\r
-void osalOsTimerHandlerI(void) {\r
-\r
-  osalDbgCheckClassI();\r
-\r
-  vtDoTickI();\r
-}\r
-\r
-/**\r
- * @brief   Checks if a reschedule is required and performs it.\r
- * @note    I-Class functions invoked from thread context must not reschedule\r
- *          by themselves, an explicit reschedule using this function is\r
- *          required in this scenario.\r
- * @note    Not implemented in this simplified OSAL.\r
- *\r
- * @sclass\r
- */\r
-void osalOsRescheduleS(void) {\r
-\r
-}\r
-\r
-/**\r
- * @brief   Current system time.\r
- * @details Returns the number of system ticks since the @p osalInit()\r
- *          invocation.\r
- * @note    The counter can reach its maximum and then restart from zero.\r
- * @note    This function can be called from any context but its atomicity\r
- *          is not guaranteed on architectures whose word size is less than\r
- *          @p systime_t size.\r
- *\r
- * @return              The system time in ticks.\r
- *\r
- * @xclass\r
- */\r
-systime_t osalOsGetSystemTimeX(void) {\r
-\r
-  return vtlist.vt_systime;\r
-}\r
-\r
-/**\r
- * @brief   Suspends the invoking thread for the specified time.\r
- *\r
- * @param[in] time      the delay in system ticks, the special values are\r
- *                      handled as follow:\r
- *                      - @a TIME_INFINITE is allowed but interpreted as a\r
- *                        normal time specification.\r
- *                      - @a TIME_IMMEDIATE this value is not allowed.\r
- *                      .\r
- *\r
- * @sclass\r
- */\r
-void osalThreadSleepS(sysinterval_t time) {\r
-  virtual_timer_t vt;\r
-  thread_reference_t tr;\r
-\r
-  tr = NULL;\r
-  vtSetI(&vt, time, callback_timeout, (void *)&tr);\r
-  osalThreadSuspendS(&tr);\r
-}\r
-\r
-/**\r
- * @brief   Suspends the invoking thread for the specified time.\r
- *\r
- * @param[in] time      the delay in system ticks, the special values are\r
- *                      handled as follow:\r
- *                      - @a TIME_INFINITE is allowed but interpreted as a\r
- *                        normal time specification.\r
- *                      - @a TIME_IMMEDIATE this value is not allowed.\r
- *                      .\r
- *\r
- * @api\r
- */\r
-void osalThreadSleep(sysinterval_t time) {\r
-\r
-  osalSysLock();\r
-  osalThreadSleepS(time);\r
-  osalSysUnlock();\r
-}\r
-\r
-/**\r
- * @brief   Sends the current thread sleeping and sets a reference variable.\r
- * @note    This function must reschedule, it can only be called from thread\r
- *          context.\r
- *\r
- * @param[in] trp       a pointer to a thread reference object\r
- * @return              The wake up message.\r
- *\r
- * @sclass\r
- */\r
-msg_t osalThreadSuspendS(thread_reference_t *trp) {\r
-  thread_t self = {MSG_WAIT};\r
-\r
-  osalDbgCheck(trp != NULL);\r
-\r
-  *trp = &self;\r
-  while (self.message == MSG_WAIT) {\r
-    osalSysUnlock();\r
-    /* A state-changing interrupt could occur here and cause the loop to\r
-       terminate, an hook macro is executed while waiting.*/\r
-    OSAL_IDLE_HOOK();\r
-    osalSysLock();\r
-  }\r
-\r
-  return self.message;\r
-}\r
-\r
-/**\r
- * @brief   Sends the current thread sleeping and sets a reference variable.\r
- * @note    This function must reschedule, it can only be called from thread\r
- *          context.\r
- *\r
- * @param[in] trp       a pointer to a thread reference object\r
- * @param[in] timeout   the timeout in system ticks, the special values are\r
- *                      handled as follow:\r
- *                      - @a TIME_INFINITE the thread enters an infinite sleep\r
- *                        state.\r
- *                      - @a TIME_IMMEDIATE the thread is not enqueued and\r
- *                        the function returns @p MSG_TIMEOUT as if a timeout\r
- *                        occurred.\r
- *                      .\r
- * @return              The wake up message.\r
- * @retval MSG_TIMEOUT  if the operation timed out.\r
- *\r
- * @sclass\r
- */\r
-msg_t osalThreadSuspendTimeoutS(thread_reference_t *trp, sysinterval_t timeout) {\r
-  msg_t msg;\r
-  virtual_timer_t vt;\r
-\r
-  osalDbgCheck(trp != NULL);\r
-\r
-  if (TIME_INFINITE == timeout)\r
-   return osalThreadSuspendS(trp);\r
-\r
-  vtSetI(&vt, timeout, callback_timeout, (void *)trp);\r
-  msg = osalThreadSuspendS(trp);\r
-  if (vtIsArmedI(&vt))\r
-    vtResetI(&vt);\r
-\r
-  return msg;\r
-}\r
-\r
-/**\r
- * @brief   Wakes up a thread waiting on a thread reference object.\r
- * @note    This function must not reschedule because it can be called from\r
- *          ISR context.\r
- *\r
- * @param[in] trp       a pointer to a thread reference object\r
- * @param[in] msg       the message code\r
- *\r
- * @iclass\r
- */\r
-void osalThreadResumeI(thread_reference_t *trp, msg_t msg) {\r
-\r
-  osalDbgCheck(trp != NULL);\r
-\r
-  if (*trp != NULL) {\r
-    (*trp)->message = msg;\r
-    *trp = NULL;\r
-  }\r
-}\r
-\r
-/**\r
- * @brief   Wakes up a thread waiting on a thread reference object.\r
- * @note    This function must reschedule, it can only be called from thread\r
- *          context.\r
- *\r
- * @param[in] trp       a pointer to a thread reference object\r
- * @param[in] msg       the message code\r
- *\r
- * @iclass\r
- */\r
-void osalThreadResumeS(thread_reference_t *trp, msg_t msg) {\r
-\r
-  osalDbgCheck(trp != NULL);\r
-\r
-  if (*trp != NULL) {\r
-    (*trp)->message = msg;\r
-    *trp = NULL;\r
-  }\r
-}\r
-\r
-/**\r
- * @brief   Enqueues the caller thread.\r
- * @details The caller thread is enqueued and put to sleep until it is\r
- *          dequeued or the specified timeouts expires.\r
- *\r
- * @param[in] tqp       pointer to the threads queue object\r
- * @param[in] timeout   the timeout in system ticks, the special values are\r
- *                      handled as follow:\r
- *                      - @a TIME_INFINITE the thread enters an infinite sleep\r
- *                        state.\r
- *                      - @a TIME_IMMEDIATE the thread is not enqueued and\r
- *                        the function returns @p MSG_TIMEOUT as if a timeout\r
- *                        occurred.\r
- *                      .\r
- * @return              The message from @p osalQueueWakeupOneI() or\r
- *                      @p osalQueueWakeupAllI() functions.\r
- * @retval MSG_TIMEOUT  if the thread has not been dequeued within the\r
- *                      specified timeout or if the function has been\r
- *                      invoked with @p TIME_IMMEDIATE as timeout\r
- *                      specification.\r
- *\r
- * @sclass\r
- */\r
-msg_t osalThreadEnqueueTimeoutS(threads_queue_t *tqp, sysinterval_t timeout) {\r
-  msg_t msg;\r
-  virtual_timer_t vt;\r
-\r
-  osalDbgCheck(tqp != NULL);\r
-\r
-  if (TIME_IMMEDIATE == timeout)\r
-    return MSG_TIMEOUT;\r
-\r
-  tqp->tr = NULL;\r
-\r
-  if (TIME_INFINITE == timeout)\r
-   return osalThreadSuspendS(&tqp->tr);\r
-\r
-  vtSetI(&vt, timeout, callback_timeout, (void *)&tqp->tr);\r
-  msg = osalThreadSuspendS(&tqp->tr);\r
-  if (vtIsArmedI(&vt))\r
-    vtResetI(&vt);\r
-\r
-  return msg;\r
-}\r
-\r
-/**\r
- * @brief   Dequeues and wakes up one thread from the queue, if any.\r
- *\r
- * @param[in] tqp       pointer to the threads queue object\r
- * @param[in] msg       the message code\r
- *\r
- * @iclass\r
- */\r
-void osalThreadDequeueNextI(threads_queue_t *tqp, msg_t msg) {\r
-\r
-  osalDbgCheck(tqp != NULL);\r
-\r
-  osalThreadResumeI(&tqp->tr, msg);\r
-}\r
-\r
-/**\r
- * @brief   Dequeues and wakes up all threads from the queue.\r
- *\r
- * @param[in] tqp       pointer to the threads queue object\r
- * @param[in] msg       the message code\r
- *\r
- * @iclass\r
- */\r
-void osalThreadDequeueAllI(threads_queue_t *tqp, msg_t msg) {\r
-\r
-  osalDbgCheck(tqp != NULL);\r
-\r
-  osalThreadResumeI(&tqp->tr, msg);\r
-}\r
-\r
-/**\r
- * @brief   Add flags to an event source object.\r
- *\r
- * @param[in] esp       pointer to the event flags object\r
- * @param[in] flags     flags to be ORed to the flags mask\r
- *\r
- * @iclass\r
- */\r
-void osalEventBroadcastFlagsI(event_source_t *esp, eventflags_t flags) {\r
-\r
-  osalDbgCheck(esp != NULL);\r
-\r
-  esp->flags |= flags;\r
-  if (esp->cb != NULL) {\r
-    esp->cb(esp);\r
-  }\r
-}\r
-\r
-/**\r
- * @brief   Add flags to an event source object.\r
- *\r
- * @param[in] esp       pointer to the event flags object\r
- * @param[in] flags     flags to be ORed to the flags mask\r
- *\r
- * @iclass\r
- */\r
-void osalEventBroadcastFlags(event_source_t *esp, eventflags_t flags) {\r
-\r
-  osalDbgCheck(esp != NULL);\r
-\r
-  osalSysLock();\r
-  osalEventBroadcastFlagsI(esp, flags);\r
-  osalSysUnlock();\r
-}\r
-\r
-/**\r
- * @brief   Event callback setup.\r
- * @note    The callback is invoked from ISR context and can\r
- *          only invoke I-Class functions. The callback is meant\r
- *          to wakeup the task that will handle the event by\r
- *          calling @p osalEventGetAndClearFlagsI().\r
- * @note    This function is not part of the OSAL API and is provided\r
- *          exclusively as an example and for convenience.\r
- *\r
- * @param[in] esp       pointer to the event flags object\r
- * @param[in] cb        pointer to the callback function\r
- * @param[in] param     parameter to be passed to the callback function\r
- *\r
- * @api\r
- */\r
-void osalEventSetCallback(event_source_t *esp,\r
-                          eventcallback_t cb,\r
-                          void *param) {\r
-\r
-  osalDbgCheck(esp != NULL);\r
-\r
-  esp->cb    = cb;\r
-  esp->param = param;\r
-}\r
-\r
-/**\r
- * @brief   Locks the specified mutex.\r
- * @post    The mutex is locked and inserted in the per-thread stack of owned\r
- *          mutexes.\r
- *\r
- * @param[in,out] mp    pointer to the @p mutex_t object\r
- *\r
- * @api\r
- */\r
-void osalMutexLock(mutex_t *mp) {\r
-\r
-  osalDbgCheck(mp != NULL);\r
-\r
-  *mp = 1;\r
-}\r
-\r
-/**\r
- * @brief   Unlocks the specified mutex.\r
- * @note    The HAL guarantees to release mutex in reverse lock order. The\r
- *          mutex being unlocked is guaranteed to be the last locked mutex\r
- *          by the invoking thread.\r
- *          The implementation can rely on this behavior and eventually\r
- *          ignore the @p mp parameter which is supplied in order to support\r
- *          those OSes not supporting a stack of the owned mutexes.\r
- *\r
- * @param[in,out] mp    pointer to the @p mutex_t object\r
- *\r
- * @api\r
- */\r
-void osalMutexUnlock(mutex_t *mp) {\r
-\r
-  osalDbgCheck(mp != NULL);\r
-\r
-  *mp = 0;\r
-}\r
-\r
-/** @} */\r
diff --git a/osal.h b/osal.h
deleted file mode 100644 (file)
index 30e1592..0000000
--- a/osal.h
+++ /dev/null
@@ -1,754 +0,0 @@
-/*\r
-    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio\r
-\r
-    Licensed under the Apache License, Version 2.0 (the "License");\r
-    you may not use this file except in compliance with the License.\r
-    You may obtain a copy of the License at\r
-\r
-        http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-    Unless required by applicable law or agreed to in writing, software\r
-    distributed under the License is distributed on an "AS IS" BASIS,\r
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-    See the License for the specific language governing permissions and\r
-    limitations under the License.\r
-*/\r
-\r
-/**\r
- * @file    osal.h\r
- * @brief   OSAL module header.\r
- *\r
- * @addtogroup OSAL\r
- * @{\r
- */\r
-\r
-#ifndef OSAL_H\r
-#define OSAL_H\r
-\r
-#include <stddef.h>\r
-#include <stdint.h>\r
-#include <stdbool.h>\r
-\r
-#include "cmparams.h"\r
-\r
-#include "osalconf.h"\r
-\r
-/*===========================================================================*/\r
-/* Module constants.                                                         */\r
-/*===========================================================================*/\r
-\r
-/**\r
- * @name    Common constants\r
- * @{\r
- */\r
-#if !defined(FALSE) || defined(__DOXYGEN__)\r
-#define FALSE                               0\r
-#endif\r
-\r
-#if !defined(TRUE) || defined(__DOXYGEN__)\r
-#define TRUE                                1\r
-#endif\r
-\r
-#define OSAL_SUCCESS                        false\r
-#define OSAL_FAILED                         true\r
-/** @} */\r
-\r
-/**\r
- * @name    Messages\r
- * @{\r
- */\r
-#define MSG_OK                              (msg_t)0\r
-#define MSG_RESET                           (msg_t)-1\r
-#define MSG_TIMEOUT                         (msg_t)-2\r
-#define MSG_WAIT                            (msg_t)-10\r
-/** @} */\r
-\r
-/**\r
- * @name    Special time constants\r
- * @{\r
- */\r
-#define TIME_IMMEDIATE                      ((sysinterval_t)0)\r
-#define TIME_INFINITE                       ((sysinterval_t)-1)\r
-/** @} */\r
-\r
-/**\r
- * @name    Systick modes.\r
- * @{\r
- */\r
-#define OSAL_ST_MODE_NONE                   0\r
-#define OSAL_ST_MODE_PERIODIC               1\r
-#define OSAL_ST_MODE_FREERUNNING            2\r
-/** @} */\r
-\r
-/**\r
- * @name    Systick parameters.\r
- * @{\r
- */\r
-/**\r
- * @brief   Size in bits of the @p systick_t type.\r
- */\r
-#define OSAL_ST_RESOLUTION                  32\r
-\r
-/**\r
- * @brief   Systick mode required by the underlying OS.\r
- */\r
-#define OSAL_ST_MODE                        OSAL_ST_MODE_NONE\r
-/** @} */\r
-\r
-/**\r
- * @name    IRQ-related constants\r
- * @{\r
- */\r
-/**\r
- * @brief   Total priority levels.\r
- */\r
-#define OSAL_IRQ_PRIORITY_LEVELS            (1U << CORTEX_PRIORITY_BITS)\r
-\r
-/**\r
- * @brief   Highest IRQ priority for HAL drivers.\r
- */\r
-#if (CORTEX_MODEL == 0) || defined(__DOXYGEN__)\r
-#define OSAL_IRQ_MAXIMUM_PRIORITY           0\r
-#else\r
-#define OSAL_IRQ_MAXIMUM_PRIORITY           1\r
-#endif\r
-\r
-/**\r
- * @brief   Converts from numeric priority to BASEPRI register value.\r
- */\r
-#define OSAL_BASEPRI(priority)              ((priority) << (8U - CORTEX_PRIORITY_BITS))\r
-/** @} */\r
-\r
-/*===========================================================================*/\r
-/* Module pre-compile time settings.                                         */\r
-/*===========================================================================*/\r
-\r
-/**\r
- * @brief   Frequency in Hertz of the system tick.\r
- */\r
-#if !defined(OSAL_ST_FREQUENCY) || defined(__DOXYGEN__)\r
-#define OSAL_ST_FREQUENCY                   1000\r
-#endif\r
-\r
-/**\r
- * @brief   Enables OSAL assertions.\r
- */\r
-#if !defined(OSAL_DBG_ENABLE_ASSERTS) || defined(__DOXYGEN__)\r
-#define OSAL_DBG_ENABLE_ASSERTS             FALSE\r
-#endif\r
-\r
-/**\r
- * @brief   Enables OSAL functions parameters checks.\r
- */\r
-#if !defined(OSAL_DBG_ENABLE_CHECKS) || defined(__DOXYGEN__)\r
-#define OSAL_DBG_ENABLE_CHECKS              FALSE\r
-#endif\r
-\r
-/**\r
- * @brief   OSAL initialization hook.\r
- */\r
-#if !defined(OSAL_INIT_HOOK) || defined(__DOXYGEN__)\r
-#define OSAL_INIT_HOOK()\r
-#endif\r
-\r
-/**\r
- * @brief   Idle loop hook macro.\r
- */\r
-#if !defined(OSAL_IDLE_HOOK) || defined(__DOXYGEN__)\r
-#define OSAL_IDLE_HOOK()\r
-#endif\r
-\r
-/*===========================================================================*/\r
-/* Derived constants and error checks.                                       */\r
-/*===========================================================================*/\r
-\r
-/*===========================================================================*/\r
-/* Module data structures and types.                                         */\r
-/*===========================================================================*/\r
-\r
-/**\r
- * @brief   Type of a system status word.\r
- */\r
-typedef uint32_t syssts_t;\r
-\r
-/**\r
- * @brief   Type of a message.\r
- */\r
-typedef int32_t msg_t;\r
-\r
-/**\r
- * @brief   Type of system time counter.\r
- */\r
-typedef uint32_t systime_t;\r
-\r
-/**\r
- * @brief   Type of system time interval.\r
- */\r
-typedef uint32_t sysinterval_t;\r
-\r
-/**\r
- * @brief   Type of realtime counter.\r
- */\r
-typedef uint32_t rtcnt_t;\r
-\r
-/**\r
- * @brief   Type of a thread.\r
- * @note    The content of this structure is not part of the API and should\r
- *          not be relied upon. Implementers may define this structure in\r
- *          an entirely different way.\r
- */\r
-typedef struct {\r
-  volatile msg_t        message;\r
-} thread_t;\r
-\r
-/**\r
- * @brief   Type of a thread reference.\r
- */\r
-typedef thread_t * thread_reference_t;\r
-\r
-/**\r
- * @brief   Type of an event flags mask.\r
- */\r
-typedef uint32_t eventflags_t;\r
-\r
-/**\r
- * @brief   Type of an event flags object.\r
- * @note    The content of this structure is not part of the API and should\r
- *          not be relied upon. Implementers may define this structure in\r
- *          an entirely different way.\r
- * @note    Retrieval and clearing of the flags are not defined in this\r
- *          API and are implementation-dependent.\r
- */\r
-typedef struct event_source event_source_t;\r
-\r
-/**\r
- * @brief   Type of an event source callback.\r
- * @note    This type is not part of the OSAL API and is provided\r
- *          exclusively as an example and for convenience.\r
- */\r
-typedef void (*eventcallback_t)(event_source_t *esp);\r
-\r
-/**\r
- * @brief   Events source object.\r
- * @note    The content of this structure is not part of the API and should\r
- *          not be relied upon. Implementers may define this structure in\r
- *          an entirely different way.\r
- * @note    Retrieval and clearing of the flags are not defined in this\r
- *          API and are implementation-dependent.\r
- */\r
-struct event_source {\r
-  volatile eventflags_t flags;      /**< @brief Stored event flags.         */\r
-  eventcallback_t       cb;         /**< @brief Event source callback.      */\r
-  void                  *param;     /**< @brief User defined field.         */\r
-};\r
-\r
-/**\r
- * @brief   Type of a mutex.\r
- * @note    If the OS does not support mutexes or there is no OS then them\r
- *          mechanism can be simulated.\r
- */\r
-typedef uint32_t mutex_t;\r
-\r
-/**\r
- * @brief   Type of a thread queue.\r
- * @details A thread queue is a queue of sleeping threads, queued threads\r
- *          can be dequeued one at time or all together.\r
- * @note    If the OSAL is implemented on a bare metal machine without RTOS\r
- *          then the queue can be implemented as a single thread reference.\r
- */\r
-typedef struct {\r
-  thread_reference_t    tr;\r
-} threads_queue_t;\r
-\r
-/*===========================================================================*/\r
-/* Module macros.                                                            */\r
-/*===========================================================================*/\r
-\r
-/**\r
- * @name    Debug related macros\r
- * @{\r
- */\r
-/**\r
- * @brief   Condition assertion.\r
- * @details If the condition check fails then the OSAL panics with a\r
- *          message and halts.\r
- * @note    The condition is tested only if the @p OSAL_ENABLE_ASSERTIONS\r
- *          switch is enabled.\r
- * @note    The remark string is not currently used except for putting a\r
- *          comment in the code about the assertion.\r
- *\r
- * @param[in] c         the condition to be verified to be true\r
- * @param[in] remark    a remark string\r
- *\r
- * @api\r
- */\r
-#define osalDbgAssert(c, remark) do {                                       \\r
-  /*lint -save -e506 -e774 [2.1, 14.3] Can be a constant by design.*/       \\r
-  if (OSAL_DBG_ENABLE_ASSERTS != FALSE) {                                   \\r
-    if (!(c)) {                                                             \\r
-  /*lint -restore*/                                                         \\r
-      osalSysHalt(__func__);                                                \\r
-    }                                                                       \\r
-  }                                                                         \\r
-} while (false)\r
-\r
-/**\r
- * @brief   Function parameters check.\r
- * @details If the condition check fails then the OSAL panics and halts.\r
- * @note    The condition is tested only if the @p OSAL_ENABLE_CHECKS switch\r
- *          is enabled.\r
- *\r
- * @param[in] c         the condition to be verified to be true\r
- *\r
- * @api\r
- */\r
-#define osalDbgCheck(c) do {                                                \\r
-  /*lint -save -e506 -e774 [2.1, 14.3] Can be a constant by design.*/       \\r
-  if (OSAL_DBG_ENABLE_CHECKS != FALSE) {                                    \\r
-    if (!(c)) {                                                             \\r
-  /*lint -restore*/                                                         \\r
-      osalSysHalt(__func__);                                                \\r
-    }                                                                       \\r
-  }                                                                         \\r
-} while (false)\r
-\r
-/**\r
- * @brief   I-Class state check.\r
- * @note    Implementation is optional.\r
- */\r
-#define osalDbgCheckClassI()\r
-\r
-/**\r
- * @brief   S-Class state check.\r
- * @note    Implementation is optional.\r
- */\r
-#define osalDbgCheckClassS()\r
-/** @} */\r
-\r
-/**\r
- * @name    IRQ service routines wrappers\r
- * @{\r
- */\r
-/**\r
- * @brief   Priority level verification macro.\r
- */\r
-#define OSAL_IRQ_IS_VALID_PRIORITY(n)                                       \\r
-  (((n) >= OSAL_IRQ_MAXIMUM_PRIORITY) && ((n) < OSAL_IRQ_PRIORITY_LEVELS))\r
-\r
-/**\r
- * @brief   IRQ prologue code.\r
- * @details This macro must be inserted at the start of all IRQ handlers.\r
- */\r
-#define OSAL_IRQ_PROLOGUE()\r
-\r
-/**\r
- * @brief   IRQ epilogue code.\r
- * @details This macro must be inserted at the end of all IRQ handlers.\r
- */\r
-#define OSAL_IRQ_EPILOGUE()\r
-\r
-/**\r
- * @brief   IRQ handler function declaration.\r
- * @details This macro hides the details of an ISR function declaration.\r
- *\r
- * @param[in] id        a vector name as defined in @p vectors.s\r
- */\r
-#define OSAL_IRQ_HANDLER(id) void id(void)\r
-/** @} */\r
-\r
-/**\r
- * @name    Time conversion utilities\r
- * @{\r
- */\r
-/**\r
- * @brief   Seconds to system ticks.\r
- * @details Converts from seconds to system ticks number.\r
- * @note    The result is rounded upward to the next tick boundary.\r
- *\r
- * @param[in] secs      number of seconds\r
- * @return              The number of ticks.\r
- *\r
- * @api\r
- */\r
-#define OSAL_S2I(secs)                                                      \\r
-  ((sysinterval_t)((uint32_t)(secs) * (uint32_t)OSAL_ST_FREQUENCY))\r
-\r
-/**\r
- * @brief   Milliseconds to system ticks.\r
- * @details Converts from milliseconds to system ticks number.\r
- * @note    The result is rounded upward to the next tick boundary.\r
- *\r
- * @param[in] msecs     number of milliseconds\r
- * @return              The number of ticks.\r
- *\r
- * @api\r
- */\r
-#define OSAL_MS2I(msecs)                                                    \\r
-  ((sysinterval_t)((((((uint32_t)(msecs)) *                                 \\r
-                  ((uint32_t)OSAL_ST_FREQUENCY)) - 1UL) / 1000UL) + 1UL))\r
-\r
-/**\r
- * @brief   Microseconds to system ticks.\r
- * @details Converts from microseconds to system ticks number.\r
- * @note    The result is rounded upward to the next tick boundary.\r
- *\r
- * @param[in] usecs     number of microseconds\r
- * @return              The number of ticks.\r
- *\r
- * @api\r
- */\r
-#define OSAL_US2I(usecs)                                                    \\r
-  ((sysinterval_t)((((((uint32_t)(usecs)) *                                 \\r
-                  ((uint32_t)OSAL_ST_FREQUENCY)) - 1UL) / 1000000UL) + 1UL))\r
-/** @} */\r
-\r
-/**\r
- * @name    Time conversion utilities for the realtime counter\r
- * @{\r
- */\r
-/**\r
- * @brief   Seconds to realtime counter.\r
- * @details Converts from seconds to realtime counter cycles.\r
- * @note    The macro assumes that @p freq >= @p 1.\r
- *\r
- * @param[in] freq      clock frequency, in Hz, of the realtime counter\r
- * @param[in] sec       number of seconds\r
- * @return              The number of cycles.\r
- *\r
- * @api\r
- */\r
-#define OSAL_S2RTC(freq, sec) ((freq) * (sec))\r
-\r
-/**\r
- * @brief   Milliseconds to realtime counter.\r
- * @details Converts from milliseconds to realtime counter cycles.\r
- * @note    The result is rounded upward to the next millisecond boundary.\r
- * @note    The macro assumes that @p freq >= @p 1000.\r
- *\r
- * @param[in] freq      clock frequency, in Hz, of the realtime counter\r
- * @param[in] msec      number of milliseconds\r
- * @return              The number of cycles.\r
- *\r
- * @api\r
- */\r
-#define OSAL_MS2RTC(freq, msec) (rtcnt_t)((((freq) + 999UL) / 1000UL) * (msec))\r
-\r
-/**\r
- * @brief   Microseconds to realtime counter.\r
- * @details Converts from microseconds to realtime counter cycles.\r
- * @note    The result is rounded upward to the next microsecond boundary.\r
- * @note    The macro assumes that @p freq >= @p 1000000.\r
- *\r
- * @param[in] freq      clock frequency, in Hz, of the realtime counter\r
- * @param[in] usec      number of microseconds\r
- * @return              The number of cycles.\r
- *\r
- * @api\r
- */\r
-#define OSAL_US2RTC(freq, usec) (rtcnt_t)((((freq) + 999999UL) / 1000000UL) * (usec))\r
-/** @} */\r
-\r
-/**\r
- * @name    Sleep macros using absolute time\r
- * @{\r
- */\r
-/**\r
- * @brief   Delays the invoking thread for the specified number of seconds.\r
- * @note    The specified time is rounded up to a value allowed by the real\r
- *          system tick clock.\r
- * @note    The maximum specifiable value is implementation dependent.\r
- *\r
- * @param[in] secs      time in seconds, must be different from zero\r
- *\r
- * @api\r
- */\r
-#define osalThreadSleepSeconds(secs) osalThreadSleep(OSAL_S2I(secs))\r
-\r
-/**\r
- * @brief   Delays the invoking thread for the specified number of\r
- *          milliseconds.\r
- * @note    The specified time is rounded up to a value allowed by the real\r
- *          system tick clock.\r
- * @note    The maximum specifiable value is implementation dependent.\r
- *\r
- * @param[in] msecs     time in milliseconds, must be different from zero\r
- *\r
- * @api\r
- */\r
-#define osalThreadSleepMilliseconds(msecs) osalThreadSleep(OSAL_MS2I(msecs))\r
-\r
-/**\r
- * @brief   Delays the invoking thread for the specified number of\r
- *          microseconds.\r
- * @note    The specified time is rounded up to a value allowed by the real\r
- *          system tick clock.\r
- * @note    The maximum specifiable value is implementation dependent.\r
- *\r
- * @param[in] usecs     time in microseconds, must be different from zero\r
- *\r
- * @api\r
- */\r
-#define osalThreadSleepMicroseconds(usecs) osalThreadSleep(OSAL_US2I(usecs))\r
-/** @} */\r
-\r
-/*===========================================================================*/\r
-/* External declarations.                                                    */\r
-/*===========================================================================*/\r
-\r
-extern const char *osal_halt_msg;\r
-\r
-#ifdef __cplusplus\r
-extern "C" {\r
-#endif\r
-  void osalInit(void);\r
-  void osalSysHalt(const char *reason);\r
-  void osalSysPolledDelayX(rtcnt_t cycles);\r
-  void osalOsTimerHandlerI(void);\r
-  void osalOsRescheduleS(void);\r
-  systime_t osalOsGetSystemTimeX(void);\r
-  void osalThreadSleepS(sysinterval_t time);\r
-  void osalThreadSleep(sysinterval_t time);\r
-  msg_t osalThreadSuspendS(thread_reference_t *trp);\r
-  msg_t osalThreadSuspendTimeoutS(thread_reference_t *trp, sysinterval_t timeout);\r
-  void osalThreadResumeI(thread_reference_t *trp, msg_t msg);\r
-  void osalThreadResumeS(thread_reference_t *trp, msg_t msg);\r
-  msg_t osalThreadEnqueueTimeoutS(threads_queue_t *tqp, sysinterval_t timeout);\r
-  void osalThreadDequeueNextI(threads_queue_t *tqp, msg_t msg);\r
-  void osalThreadDequeueAllI(threads_queue_t *tqp, msg_t msg);\r
-  void osalEventBroadcastFlagsI(event_source_t *esp, eventflags_t flags);\r
-  void osalEventBroadcastFlags(event_source_t *esp, eventflags_t flags);\r
-  void osalEventSetCallback(event_source_t *esp,\r
-                            eventcallback_t cb,\r
-                            void *param);\r
-  void osalMutexLock(mutex_t *mp);\r
-  void osalMutexUnlock(mutex_t *mp);\r
-#ifdef __cplusplus\r
-}\r
-#endif\r
-\r
-/*===========================================================================*/\r
-/* Module inline functions.                                                  */\r
-/*===========================================================================*/\r
-\r
-/**\r
- * @brief   Disables interrupts globally.\r
- *\r
- * @special\r
- */\r
-static inline void osalSysDisable(void) {\r
-\r
-  __disable_irq();\r
-}\r
-\r
-/**\r
- * @brief   Enables interrupts globally.\r
- *\r
- * @special\r
- */\r
-static inline void osalSysEnable(void) {\r
-\r
-  __enable_irq();\r
-}\r
-\r
-/**\r
- * @brief   Enters a critical zone from thread context.\r
- * @note    This function cannot be used for reentrant critical zones.\r
- *\r
- * @special\r
- */\r
-static inline void osalSysLock(void) {\r
-\r
-#if CORTEX_MODEL == 0\r
-  __disable_irq();\r
-#else\r
-  __set_BASEPRI(OSAL_BASEPRI(OSAL_IRQ_MAXIMUM_PRIORITY));\r
-#endif\r
-}\r
-\r
-/**\r
- * @brief   Leaves a critical zone from thread context.\r
- * @note    This function cannot be used for reentrant critical zones.\r
- *\r
- * @special\r
- */\r
-static inline void osalSysUnlock(void) {\r
-\r
-#if CORTEX_MODEL == 0\r
-  __enable_irq();\r
-#else\r
-  __set_BASEPRI(0);\r
-#endif\r
-}\r
-\r
-/**\r
- * @brief   Enters a critical zone from ISR context.\r
- * @note    This function cannot be used for reentrant critical zones.\r
- *\r
- * @special\r
- */\r
-static inline void osalSysLockFromISR(void) {\r
-\r
-#if CORTEX_MODEL == 0\r
-  __disable_irq();\r
-#else\r
-  __set_BASEPRI(OSAL_BASEPRI(OSAL_IRQ_MAXIMUM_PRIORITY));\r
-#endif\r
-}\r
-\r
-/**\r
- * @brief   Leaves a critical zone from ISR context.\r
- * @note    This function cannot be used for reentrant critical zones.\r
- *\r
- * @special\r
- */\r
-static inline void osalSysUnlockFromISR(void) {\r
-\r
-#if CORTEX_MODEL == 0\r
-  __enable_irq();\r
-#else\r
-  __set_BASEPRI(0);\r
-#endif\r
-}\r
-\r
-/**\r
- * @brief   Returns the execution status and enters a critical zone.\r
- * @details This functions enters into a critical zone and can be called\r
- *          from any context. Because its flexibility it is less efficient\r
- *          than @p chSysLock() which is preferable when the calling context\r
- *          is known.\r
- * @post    The system is in a critical zone.\r
- *\r
- * @return              The previous system status, the encoding of this\r
- *                      status word is architecture-dependent and opaque.\r
- *\r
- * @xclass\r
- */\r
-static inline syssts_t osalSysGetStatusAndLockX(void) {\r
-  syssts_t sts;\r
-\r
-#if CORTEX_MODEL == 0\r
-  sts = (syssts_t)__get_PRIMASK();\r
-  __disable_irq();\r
-#else\r
-  sts = (syssts_t)__get_BASEPRI();\r
-  __set_BASEPRI(OSAL_BASEPRI(OSAL_IRQ_MAXIMUM_PRIORITY));\r
-#endif\r
-  return sts;\r
-}\r
-\r
-/**\r
- * @brief   Restores the specified execution status and leaves a critical zone.\r
- * @note    A call to @p chSchRescheduleS() is automatically performed\r
- *          if exiting the critical zone and if not in ISR context.\r
- *\r
- * @param[in] sts       the system status to be restored.\r
- *\r
- * @xclass\r
- */\r
-static inline void osalSysRestoreStatusX(syssts_t sts) {\r
-\r
-#if CORTEX_MODEL == 0\r
-  if ((sts & (syssts_t)1) == (syssts_t)0) {\r
-    __enable_irq();\r
-  }\r
-#else\r
-  __set_BASEPRI(sts);\r
-#endif\r
-}\r
-\r
-/**\r
- * @brief   Adds an interval to a system time returning a system time.\r
- *\r
- * @param[in] systime   base system time\r
- * @param[in] interval  interval to be added\r
- * @return              The new system time.\r
- *\r
- * @xclass\r
- */\r
-static inline systime_t osalTimeAddX(systime_t systime,\r
-                                     sysinterval_t interval) {\r
-\r
-  return systime + (systime_t)interval;\r
-}\r
-\r
-/**\r
- * @brief   Subtracts two system times returning an interval.\r
- *\r
- * @param[in] start     first system time\r
- * @param[in] end       second system time\r
- * @return              The interval representing the time difference.\r
- *\r
- * @xclass\r
- */\r
-static inline sysinterval_t osalTimeDiffX(systime_t start, systime_t end) {\r
-\r
-  return (sysinterval_t)((systime_t)(end - start));\r
-}\r
-\r
-/**\r
- * @brief   Checks if the specified time is within the specified time window.\r
- * @note    When start==end then the function returns always false because the\r
- *          time window has zero size.\r
- * @note    This function can be called from any context.\r
- *\r
- * @param[in] time      the time to be verified\r
- * @param[in] start     the start of the time window (inclusive)\r
- * @param[in] end       the end of the time window (non inclusive)\r
- * @retval true         current time within the specified time window.\r
- * @retval false        current time not within the specified time window.\r
- *\r
- * @xclass\r
- */\r
-static inline bool osalTimeIsInRangeX(systime_t time,\r
-                                      systime_t start,\r
-                                      systime_t end) {\r
-\r
-  return (bool)((systime_t)((systime_t)time - (systime_t)start) <\r
-                (systime_t)((systime_t)end - (systime_t)start));\r
-}\r
-\r
-/**\r
- * @brief   Initializes a threads queue object.\r
- *\r
- * @param[out] tqp      pointer to the threads queue object\r
- *\r
- * @init\r
- */\r
-static inline void osalThreadQueueObjectInit(threads_queue_t *tqp) {\r
-\r
-  osalDbgCheck(tqp != NULL);\r
-}\r
-\r
-/**\r
- * @brief   Initializes an event source object.\r
- *\r
- * @param[out] esp      pointer to the event source object\r
- *\r
- * @init\r
- */\r
-static inline void osalEventObjectInit(event_source_t *esp) {\r
-\r
-  osalDbgCheck(esp != NULL);\r
-\r
-  esp->flags = (eventflags_t)0;\r
-  esp->cb    = NULL;\r
-  esp->param = NULL;\r
-}\r
-\r
-/**\r
- * @brief   Initializes s @p mutex_t object.\r
- *\r
- * @param[out] mp       pointer to the @p mutex_t object\r
- *\r
- * @init\r
- */\r
-static inline void osalMutexObjectInit(mutex_t *mp) {\r
-\r
-  osalDbgCheck(mp != NULL);\r
-\r
-  *mp = 0;\r
-}\r
-\r
-#endif /* OSAL_H */\r
-\r
-/** @} */\r
diff --git a/source/2048.c b/source/2048.c
new file mode 100644 (file)
index 0000000..ce73844
--- /dev/null
@@ -0,0 +1,104 @@
+#include "buttons.h"
+#include "dogs.h"
+
+static int values[16];
+
+void g2048_init()
+{
+    for (int i = 0; i < 16; i++)
+        values[i] = 0;
+}
+
+int g2048_loop()
+{
+    if ((button_state & BUTTON_JOYUP) == BUTTON_JOYUP) {
+        for (int x = 0; x < 3; x++) {
+            for (int y = 0; y < 3; y++) {
+
+                if (values[4 * y + x] != 0)
+                    continue;
+            }
+        }
+
+        for (int y = 3; y > 0; y--) {
+            for (int x = 0; x < 4; x++) {
+                if (values[4 * y + x] != 0) {
+                    if (values[4 * (y - 1) + x] == 0)
+                        values[4 * (y - 1) + x] = values[4 * y + x], values[4 * y + x] = 0;
+                    else if (values[4 * (y - 1) + x] == values[4 * y + x])
+                        values[4 * (y - 1) + x]++, values[4 * y + x] = 0;
+                }
+            }
+        }
+
+        for (int i = 15; i >= 0; i--) {
+            if (values[i] == 0) {
+                values[i] = 1;
+                break;
+            }
+        }
+    } else if ((button_state & BUTTON_JOYDOWN) == BUTTON_JOYDOWN) {
+        for (int y = 0; y < 3; y++) {
+            for (int x = 0; x < 4; x++) {
+                if (values[4 * y + x] != 0) {
+                    if (values[4 * (y + 1) + x] == 0)
+                        values[4 * (y + 1) + x] = values[4 * y + x], values[4 * y + x] = 0;
+                    else if (values[4 * (y + 1) + x] == values[4 * y + x])
+                        values[4 * (y + 1) + x]++, values[4 * y + x] = 0;
+                }
+            }
+        }
+
+        for (int i = 15; i >= 0; i--) {
+            if (values[i] == 0) {
+                values[i] = 1;
+                break;
+            }
+        }
+    } else if ((button_state & BUTTON_JOYLEFT) == BUTTON_JOYLEFT) {
+        for (int x = 3; x > 0; x--) {
+            for (int y = 0; y < 4; y++) {
+                if (values[4 * y + x] != 0) {
+                    if (values[4 * y + x - 1] == 0)
+                        values[4 * y + x - 1] = values[4 * y + x], values[4 * y + x] = 0;
+                    else if (values[4 * y + x - 1] == values[4 * y + x])
+                        values[4 * y + x - 1]++, values[4 * y + x] = 0;
+                }
+            }
+        }
+
+        for (int i = 15; i >= 0; i--) {
+            if (values[i] == 0) {
+                values[i] = 1;
+                break;
+            }
+        }
+    } else if ((button_state & BUTTON_JOYRIGHT) == BUTTON_JOYRIGHT) {
+        for (int x = 0; x < 3; x++) {
+            for (int y = 0; y < 4; y++) {
+                if (values[4 * y + x] != 0) {
+                    if (values[4 * y + x + 1] == 0)
+                        values[4 * y + x + 1] = values[4 * y + x], values[4 * y + x] = 0;
+                    else if (values[4 * y + x + 1] == values[4 * y + x])
+                        values[4 * y + x + 1]++, values[4 * y + x] = 0;
+                }
+            }
+        }
+
+        for (int i = 15; i >= 0; i--) {
+            if (values[i] == 0) {
+                values[i] = 1;
+                break;
+            }
+        }
+    }
+
+    dogs_clear();
+    for (int i = 0; i < 16; i++) {
+        if (values[i] != 0)
+            draw_number(31 + 10 * (i % 4), 12 + 10 * (3 - (i / 4)), values[i]);
+    }
+    dogs_flush();
+
+    return 500;
+}
diff --git a/source/2048.h b/source/2048.h
new file mode 100644 (file)
index 0000000..b8bdf14
--- /dev/null
@@ -0,0 +1,3 @@
+void g2048_init();
+int g2048_loop();
+
diff --git a/source/buttons.c b/source/buttons.c
new file mode 100644 (file)
index 0000000..45ea7bd
--- /dev/null
@@ -0,0 +1,58 @@
+/**
+ * buttons.c - Provides ability to read button state.
+ * Copyright (C) 2020  Clyne Sullivan
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * See the GNU General Public License for more details.
+ */
+
+#include "buttons.h"
+#include "hal.h"
+
+unsigned char button_state = 0;
+
+static void buttonStateHandler(void *arg)
+{
+    int pad = (unsigned int)arg & 0xFF;
+    int bit = 1 << ((unsigned int)arg >> 8);
+
+    if (!palReadPad(GPIOA, pad)) {
+        if ((button_state & bit) != bit)
+            button_state |= bit;
+    } else {
+        if ((button_state & bit) == bit)
+            button_state &= ~(bit);
+    }
+}
+
+void buttons_init()
+{
+    palSetPadMode(GPIOA, 0, PAL_MODE_INPUT_PULLUP);   // Joy A (UL)
+    palSetPadMode(GPIOA, 1, PAL_MODE_INPUT_PULLUP);   // Joy B (UR)
+    palSetPadMode(GPIOA, 2, PAL_MODE_INPUT_PULLUP);   // Joy C (DR)
+    palSetPadMode(GPIOA, 3, PAL_MODE_INPUT_PULLUP);   // Joy D (DL)
+    palSetPadMode(GPIOA, 6, PAL_MODE_INPUT_PULLUP);   // Joy button
+    palSetPadMode(GPIOA, 7, PAL_MODE_INPUT_PULLUP);   // Button 1
+    palSetPadMode(GPIOA, 9, PAL_MODE_INPUT_PULLUP);   // Button 2
+    palSetPadMode(GPIOA, 10, PAL_MODE_INPUT_PULLUP);  // Button 3
+    palEnablePadEvent(GPIOA, 0, PAL_EVENT_MODE_BOTH_EDGES);
+    palEnablePadEvent(GPIOA, 1, PAL_EVENT_MODE_BOTH_EDGES);
+    palEnablePadEvent(GPIOA, 2, PAL_EVENT_MODE_BOTH_EDGES);
+    palEnablePadEvent(GPIOA, 3, PAL_EVENT_MODE_BOTH_EDGES);
+    palEnablePadEvent(GPIOA, 6, PAL_EVENT_MODE_BOTH_EDGES);
+    palEnablePadEvent(GPIOA, 7, PAL_EVENT_MODE_BOTH_EDGES);
+    palEnablePadEvent(GPIOA, 9, PAL_EVENT_MODE_BOTH_EDGES);
+    palEnablePadEvent(GPIOA, 10, PAL_EVENT_MODE_BOTH_EDGES);
+    palSetPadCallback(GPIOA, 0, buttonStateHandler, (void *)0x0700);
+    palSetPadCallback(GPIOA, 1, buttonStateHandler, (void *)0x0601);
+    palSetPadCallback(GPIOA, 2, buttonStateHandler, (void *)0x0502);
+    palSetPadCallback(GPIOA, 3, buttonStateHandler, (void *)0x0403);
+    palSetPadCallback(GPIOA, 6, buttonStateHandler, (void *)0x0306);
+    palSetPadCallback(GPIOA, 7, buttonStateHandler, (void *)0x0207);
+    palSetPadCallback(GPIOA, 9, buttonStateHandler, (void *)0x0109);
+    palSetPadCallback(GPIOA, 10, buttonStateHandler, (void *)0x000A);
+}
+
diff --git a/source/buttons.h b/source/buttons.h
new file mode 100644 (file)
index 0000000..ba7e02d
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ * buttons.h - Provides ability to read button state.
+ * Copyright (C) 2020  Clyne Sullivan
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * See the GNU General Public License for more details.
+ */
+
+#ifndef BUTTONS_H_
+#define BUTTONS_H_
+
+#define BUTTON_JOYUL (1 << 7)
+#define BUTTON_JOYUR (1 << 6)
+#define BUTTON_JOYDR (1 << 5)
+#define BUTTON_JOYDL (1 << 4)
+#define BUTTON_JOY   (1 << 3)
+#define BUTTON_1     (1 << 2)
+#define BUTTON_2     (1 << 1)
+#define BUTTON_3     (1 << 0)
+
+#define BUTTON_JOYUP    (BUTTON_JOYUL | BUTTON_JOYUR)
+#define BUTTON_JOYDOWN  (BUTTON_JOYDL | BUTTON_JOYDR)
+#define BUTTON_JOYLEFT  (BUTTON_JOYUL | BUTTON_JOYDL)
+#define BUTTON_JOYRIGHT (BUTTON_JOYUR | BUTTON_JOYDR)
+
+extern unsigned char button_state;
+
+void buttons_init();
+
+#endif // BUTTONS_H_
+
diff --git a/source/dogs.c b/source/dogs.c
new file mode 100644 (file)
index 0000000..b986845
--- /dev/null
@@ -0,0 +1,356 @@
+/**
+ * dogs.c - Interface for drawing to the EADOGS102N-6 display.
+ * Copyright (C) 2020  Clyne Sullivan
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * See the GNU General Public License for more details.
+ */
+
+//#include "ch.h"
+#include "dogs.h"
+#include "hal.h"
+
+#define SET_DATA palSetPad(GPIOC, 15)
+#define SET_CMD  palClearPad(GPIOC, 15)
+#define CS_HIGH  palSetPad(GPIOA, 4)
+#define CS_LOW   palClearPad(GPIOA, 4)
+unsigned char dogs_buffer[DISP_WIDTH * DISP_HEIGHT / 8];
+
+//static volatile bool dogs_spi_done = false;
+
+#define spi_send(data, len) spiSend(&SPID1, len, data)
+//static void spi_send(unsigned char *data, unsigned int len)
+//{
+    //dogs_spi_done = false;
+    //spiStartSend(&SPID1, len, data);
+    //while (!dogs_spi_done)
+    //    asm("wfi");
+
+    //for (; len > 0; --len)
+    //    spiPolledExchange(&SPID1, *data++);
+//}
+
+static void dogs_init_display();
+//static void dogs_spi_callback(SPIDriver *spid)
+//{
+//    if (spiIsBufferComplete(spid))
+//        dogs_spi_done = true;
+//}
+
+void dogs_init()
+{
+    // SPI
+    palSetPadMode(GPIOB, 1, PAL_MODE_ALTERNATE(1));     // MOSI
+    palSetPadMode(GPIOA, 5, PAL_MODE_ALTERNATE(0));     // CLK
+    palSetPadMode(GPIOA, 4, PAL_MODE_OUTPUT_PUSHPULL);  // nCS
+    palSetPadMode(GPIOC, 14, PAL_MODE_OUTPUT_PUSHPULL); // nRST
+    palSetPadMode(GPIOC, 15, PAL_MODE_OUTPUT_PUSHPULL); // CD
+
+    palSetPad(GPIOA, 4);
+    palSetPad(GPIOC, 14);
+    palClearPad(GPIOC, 15);
+
+    static const SPIConfig spicfg = {
+        false,
+        NULL /*dogs_spi_callback*/,
+        0, // cr1
+        0
+    };
+    spiStart(&SPID1, &spicfg);
+
+    dogs_init_display();
+    dogs_clear();
+    dogs_flush();
+}
+
+void dogs_write_cmd(unsigned char byte)
+{
+    spi_send(&byte, 1);
+}
+
+void dogs_set_column(unsigned int col)
+{
+    dogs_write_cmd(0x10 | ((col >> 4) & 0xF));
+    dogs_write_cmd(0x00 | (col & 0xF));
+}
+void dogs_set_power(unsigned int bits)
+{
+    dogs_write_cmd(0x28 | (bits & 0x7));
+}
+void dogs_set_scroll_line(unsigned int startline)
+{
+    dogs_write_cmd(0x40 | (startline & 0x3F));
+}
+void dogs_set_page(unsigned int page)
+{
+    dogs_write_cmd(0xB0 | (page & 0xF));
+}
+void dogs_set_vlcd_ratio(unsigned int ratio)
+{
+    dogs_write_cmd(0x20 | (ratio & 0x7));
+}
+void dogs_set_contrast(unsigned int value)
+{
+    dogs_write_cmd(0x81);
+    dogs_write_cmd(0x00 | (value & 0x3F));
+}
+void dogs_set_pixelson(bool on)
+{
+    dogs_write_cmd(on ? 0xA5 : 0xA4);
+}
+void dogs_set_invert(bool invert)
+{
+    dogs_write_cmd(invert ? 0xA7 : 0xA6);
+}
+void dogs_set_sleep(bool sleep)
+{
+    dogs_write_cmd(sleep ? 0xAE : 0xAF);
+}
+void dogs_set_segdir(bool normal)
+{
+    dogs_write_cmd(normal ? 0xA0 : 0xA1);
+}
+void dogs_set_comdir(bool normal)
+{
+    dogs_write_cmd(normal ? 0xC0 : 0xC8);
+}
+void dogs_reset()
+{
+    dogs_write_cmd(0xE2);
+}
+void dogs_set_bias(bool higher)
+{
+    dogs_write_cmd(higher ? 0xA2 : 0xA3);
+}
+void dogs_set_advanced(unsigned int bits)
+{
+    dogs_write_cmd(0xFA);
+    dogs_write_cmd(0x10 | bits);
+}
+
+void dogs_init_display()
+{
+    SET_CMD;
+    CS_LOW;
+    dogs_reset();
+    CS_HIGH;
+
+    unsigned long int reset_sleep = (STM32_SYSCLK / 1000) * 100;
+    while (reset_sleep != 0) {
+        asm("nop; nop; nop; nop; nop");
+        reset_sleep -= 8;
+    }
+
+    CS_LOW;
+    dogs_set_scroll_line(0);
+    dogs_set_segdir(true);
+    dogs_set_comdir(false);
+    dogs_set_pixelson(false);
+    dogs_set_invert(false);
+    dogs_set_bias(true);
+    dogs_set_power(0x07);
+    dogs_set_vlcd_ratio(7);
+    dogs_set_contrast(12);
+    dogs_set_advanced(0x83);
+    dogs_set_sleep(false);
+    CS_HIGH;
+}
+
+void dogs_clear()
+{
+    uint32_t *ptr = (uint32_t *)dogs_buffer;
+    unsigned int count = sizeof(dogs_buffer) / sizeof(uint32_t) / 12;
+
+    for (; count; --count) {
+        *ptr++ = 0;
+        *ptr++ = 0;
+        *ptr++ = 0;
+        *ptr++ = 0;
+        *ptr++ = 0;
+        *ptr++ = 0;
+        *ptr++ = 0;
+        *ptr++ = 0;
+        *ptr++ = 0;
+        *ptr++ = 0;
+        *ptr++ = 0;
+        *ptr++ = 0;
+    }
+}
+
+void dogs_flush()
+{
+    unsigned char *ptr = dogs_buffer;
+    CS_LOW;
+    for (int page = 0; page < 8; ++page) {
+        SET_CMD;
+        dogs_set_page(page);
+        dogs_set_column(30);
+
+        SET_DATA;
+        spi_send(ptr, 102);
+        ptr += 102;
+    }
+    CS_HIGH;
+}
+
+void draw_pixel(int x, int y, bool state)
+{
+    if (x < 0 || y < 0 || x >= DISP_WIDTH || y >= DISP_HEIGHT)
+        return;
+    y = DISP_HEIGHT - 1 - y;
+    if (state)
+        dogs_buffer[y / 8 * DISP_WIDTH + x] |= (1 << (y % 8));
+    else
+        dogs_buffer[y / 8 * DISP_WIDTH + x] &= ~(1 << (y % 8));
+}
+
+void draw_rect(int x, int y, int w, int h)
+{
+    for (int i = 0; i < w; i++) {
+        for (int j = 0; j < h; j++)
+            draw_pixel(x + i, y + j, true);
+    }
+}
+
+void draw_bitmap(int x, int y, const unsigned char *buffer)
+{
+    // Prepare source information
+    const unsigned char *src = buffer;
+    const int width = *src++;
+    const int height = *src++;
+    int sbit = 0;
+
+    for (int j = 0; j < height; j++) {
+        for (int i = 0; i < width; i++) {
+            draw_pixel(x + i, y + j, *src & (1 << sbit));
+            if (++sbit == 8) {
+                sbit = 0;
+                ++src;
+            }
+        }
+    }
+}
+
+static const unsigned char draw_number_bitmaps[10][10] = {
+    { 8, 8, // '0'
+        0b00011000,
+        0b00100100,
+        0b01000010,
+        0b01000010,
+        0b01000010,
+        0b01000010,
+        0b00100100,
+        0b00011000,
+    },
+    { 8, 8, // '1'
+        0b01111100,
+        0b00010000,
+        0b00010000,
+        0b00010000,
+        0b00010000,
+        0b00010000,
+        0b00010100,
+        0b00011000,
+    },
+    { 8, 8, // '2'
+        0b01111110,
+        0b00001000,
+        0b00010000,
+        0b00100000,
+        0b01000000,
+        0b01000010,
+        0b00100100,
+        0b00011000,
+    },
+    { 8, 8, // '3'
+        0b00011100,
+        0b00100010,
+        0b01000000,
+        0b00100000,
+        0b00111100,
+        0b01000000,
+        0b00100010,
+        0b00011100,
+    },
+    { 8, 8, // '4'
+        0b00100000,
+        0b00100000,
+        0b00100000,
+        0b00111110,
+        0b00100100,
+        0b00101000,
+        0b00110000,
+        0b00100000,
+    },
+    { 8, 8, // '5'
+        0b00011100,
+        0b00100010,
+        0b01000000,
+        0b01000000,
+        0b00100000,
+        0b00011110,
+        0b00000010,
+        0b01111110,
+    },
+    { 8, 8, // '6'
+        0b00011000,
+        0b00100100,
+        0b01000010,
+        0b01000110,
+        0b00111010,
+        0b00000010,
+        0b00000100,
+        0b00111000,
+    },
+    { 8, 8, // '7'
+        0b00001000,
+        0b00001000,
+        0b00001000,
+        0b00001000,
+        0b00010000,
+        0b00100000,
+        0b01000000,
+        0b01111110,
+    },
+    { 8, 8, // '8'
+        0b00011000,
+        0b00100100,
+        0b01000010,
+        0b00100100,
+        0b00111100,
+        0b01000010,
+        0b00100100,
+        0b00011000,
+    },
+    { 8, 8, // '9'
+        0b00011100,
+        0b00100010,
+        0b01000000,
+        0b01111000,
+        0b01000100,
+        0b01000010,
+        0b00100100,
+        0b00011000,
+    },
+};
+
+void draw_number(int x, int y, int number)
+{
+    if (number < 0)
+        number = -number;
+    int tmp = number;
+    int count;
+    for (count = 0; tmp; count++)
+        tmp /= 10;
+    if (count == 0)
+        count = 1;
+    x += count * 8;
+    do {
+        x -= 8;
+        draw_bitmap(x, y, draw_number_bitmaps[number % 10]);
+    } while (number /= 10);
+}
+
diff --git a/source/dogs.h b/source/dogs.h
new file mode 100644 (file)
index 0000000..8af24fd
--- /dev/null
@@ -0,0 +1,33 @@
+/**
+ * dogs.h - Interface for drawing to the EADOGS102N-6 display.
+ * Copyright (C) 2020  Clyne Sullivan
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * See the GNU General Public License for more details.
+ */
+
+#ifndef DOGS_H_
+#define DOGS_H_
+
+#include <stdbool.h>
+
+#define DISP_WIDTH  102
+#define DISP_HEIGHT 64
+
+extern unsigned char dogs_buffer[DISP_WIDTH * DISP_HEIGHT / 8];
+
+void dogs_init();
+void dogs_clear();
+void dogs_flush();
+void dogs_set_sleep(bool sleep);
+
+void draw_pixel(int x, int y, bool state);
+void draw_rect(int x, int y, int w, int h);
+void draw_bitmap(int x, int y, const unsigned char *buffer);
+void draw_number(int x, int y, int number);
+
+#endif // DOGS_H_
+
diff --git a/source/flapbird.c b/source/flapbird.c
new file mode 100644 (file)
index 0000000..f2dd2cf
--- /dev/null
@@ -0,0 +1,80 @@
+#include "buttons.h"
+#include "dogs.h"
+
+static const unsigned char bird[] = {
+    8, 8,
+    0b00111100,
+    0b01100110,
+    0b01000010,
+    0b01111110,
+    0b01100110,
+    0b01000010,
+    0b11000000,
+    0b11000000,
+};
+
+static int score;
+static int t1x, t1o;
+static int t2x, t2o;
+static int py;
+static int vy;
+static int counter;
+
+void flapbird_init()
+{
+    score = 0;
+    t1x = DISP_WIDTH / 2, t1o = 15;
+    t2x = DISP_WIDTH, t2o = 49;
+    py = DISP_HEIGHT / 2 - 4;
+    vy = 0;
+    counter = 0;
+}
+
+int flapbird_loop()
+{
+    // Player logic
+    if (py > 0) {
+        py += vy;
+        if (vy > -3)
+            vy--;
+    } else {
+        if (py < 0)
+            py = 0;
+        if (score > 0)
+            score = 0;
+    }
+
+    if (button_state & BUTTON_2) {
+        vy = 5;
+        if (py <= 0)
+            py = 1;
+    }
+
+    // Rendering
+    dogs_clear();
+
+    draw_rect(t1x, 0, 4, t1o - 10);
+    draw_rect(t1x, t1o + 10, 4, DISP_HEIGHT - t1o + 10);
+    draw_rect(t2x, 0, 4, t2o - 10);
+    draw_rect(t2x, t2o + 10, 4, DISP_HEIGHT - t2o + 10);
+    draw_bitmap(4, py, bird);
+
+    draw_number(DISP_WIDTH - 25, DISP_HEIGHT - 8, score);
+    dogs_flush();
+
+    // Game logic
+    if (t1x == 4)
+        score = (py + 2 > t1o - 10 && py + 6 < t1o + 10) ? score + 1 : 0;
+    if (t2x == 4)
+        score = (py + 2 > t2o - 10 && py + 6 < t2o + 10) ? score + 1 : 0;
+
+    t1x -= 2;
+    if (t1x <= -5)
+        t1x = DISP_WIDTH;
+    t2x -= 2;
+    if (t2x <= -5)
+        t2x = DISP_WIDTH;
+
+    return 100;
+}
+
diff --git a/source/flapbird.h b/source/flapbird.h
new file mode 100644 (file)
index 0000000..7ab4199
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef FLAPBIRD_H_
+#define FLAPBIRD_H_
+
+void flapbird_init();
+int flapbird_loop();
+
+#endif // FLAPBIRD_H_
+
diff --git a/source/main.c b/source/main.c
new file mode 100644 (file)
index 0000000..fd753ea
--- /dev/null
@@ -0,0 +1,150 @@
+/**
+ * main.c - Firmware entry point and main loop for game or testing.
+ * Copyright (C) 2020  Clyne Sullivan
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * See the GNU General Public License for more details.
+ */
+
+#include "buttons.h"
+#include "dogs.h"
+#include "hal.h"
+
+//#include "2048.h"
+#include "flapbird.h"
+
+/*
+ * Progress:
+ *  - Serial through LPUART1 works (38400 baud, takes over swdio pins)
+ *  - Display comm. over SPI, can clear screen
+ *  - Can read buttons through PAL (through interrupts now)
+ *  - Use ADC to read Vintref, print to screen in mV
+ *  - Sleep mode via WFI, saves ~0.5mA (we're running around 1.1mA)
+ *  - Run at 512kHz, only use HSI for ADC: 360uA (jumpy)
+ *  - Drop to 1.2V Vcore (range 3), enable low-V detector: 375uA (steady) (440uA at 1MHz)
+ *  - Run at 4MHz, drop to low-power run/sleep @ 64kHz for idle: 375uA (also lowered contrast)
+ *  - Sleep display for 'pause': ~240uA
+ *
+ *  - Use RTC for delay, Stop mode when idle: 348uA
+ *
+ *  - Flappy bird is going, 2048 next
+ */
+
+static int readVddmv();
+
+static void alarm_callback(RTCDriver *rtcp, rtcevent_t event)
+{
+    (void)rtcp;
+    (void)event;
+
+    static bool sleep = false;
+
+    bool sleep_button = (button_state & BUTTON_1) != 0;
+    if (sleep && !sleep_button)
+        return;
+
+    RCC->ICSCR |= 6 << RCC_ICSCR_MSIRANGE_Pos;
+    dogs_set_sleep(false);
+
+    if (sleep_button) {
+        sleep ^= true;
+        if (sleep) {
+            draw_number(DISP_WIDTH - 33, 0,
+                        !(PWR->CSR & PWR_CSR_PVDO) ? readVddmv() : 1);
+            dogs_flush();
+        }
+    }
+
+    if (!sleep)
+        flapbird_loop();
+
+    dogs_set_sleep(true);
+}
+
+int main(void)
+{
+    halInit();
+    //chSysInit();
+    buttons_init();
+
+    dogs_init();
+    flapbird_init();
+
+    static const RTCWakeup wakeupcfg = {
+        (0 << 16) | // wucksel (37k /16 = ~2k)
+        200         // wut (hope for 10Hz)
+    };
+    rtcSTM32SetPeriodicWakeup(&RTCD1, &wakeupcfg);
+    rtcSetCallback(&RTCD1, alarm_callback);
+
+    RCC->CR &= ~RCC_CR_HSION;
+    PWR->CR |= PWR_CR_LPSDSR | PWR_CR_ULP;
+    PWR->CR |= PWR_CR_LPRUN;
+    SCB->SCR = 6;
+    //FLASH->ACR |= FLASH_ACR_SLEEP_PD;
+
+    // Below code for serial -- note that it cuts off debugging, and MUST be used in a thread
+    //chThdSleepMilliseconds(2000);
+    //palSetPadMode(GPIOA, 13, PAL_MODE_ALTERNATE(6));
+    //palSetPadMode(GPIOA, 14, PAL_MODE_ALTERNATE(6));
+    //sdStart(&LPSD1, NULL);
+    //chnWrite(&LPSD1, (const uint8_t *)"Hello World!\r\n", 14);
+
+    /* This is now the idle thread loop, you may perform here a low priority
+       task but YOU MUST NEVER TRY TO SLEEP OR WAIT in this loop. Note that
+       this tasks runs at the lowest priority level so any instruction added
+       here will be executed after all other tasks have been started. */
+    while (1)
+        asm("wfe");
+}
+
+void HardFault_Handler()
+{
+    while (1);
+}
+
+static volatile bool adc_is_complete = false;
+static void adc_callback(ADCDriver *adcd)
+{
+    (void)adcd;
+    adc_is_complete = true;
+}
+
+static const ADCConfig adccfg = {
+    .dummy = 0
+};
+
+static const ADCConversionGroup adcgrpcfg = {
+  .circular     = false,
+  .num_channels = 1,
+  .end_cb       = adc_callback,
+  .error_cb     = NULL,
+  .cfgr1        = ADC_CFGR1_RES_12BIT,     /* CFGR1 */
+  .cfgr2        = 0,                       /* CFGR2 */
+  .tr           = ADC_TR(0, 0),            /* TR */
+  .smpr         = ADC_SMPR_SMP_1P5,        /* SMPR */
+  .chselr       = ADC_CHSELR_CHSEL17       /* CHSELR */
+};
+
+int readVddmv()
+{
+    adcsample_t reading = 0;
+
+    RCC->CR |= RCC_CR_HSION;
+    while (!(RCC->CR & RCC_CR_HSIRDY));
+
+    adcStart(&ADCD1, &adccfg);
+    adcSTM32EnableVREF(&ADCD1);
+    adcStartConversion(&ADCD1, &adcgrpcfg, &reading, 1);
+    while (!adc_is_complete);
+    adcStopConversion(&ADCD1);
+    adcSTM32DisableVREF(&ADCD1);
+    adcStop(&ADCD1);
+
+    RCC->CR &= ~RCC_CR_HSION;
+
+    return 3000 * /* CAL */ *((adcsample_t *)0x1FF80078) / reading;
+}
diff --git a/source/osal.c b/source/osal.c
new file mode 100644 (file)
index 0000000..5c62069
--- /dev/null
@@ -0,0 +1,467 @@
+/*\r
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio\r
+\r
+    Licensed under the Apache License, Version 2.0 (the "License");\r
+    you may not use this file except in compliance with the License.\r
+    You may obtain a copy of the License at\r
+\r
+        http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+    Unless required by applicable law or agreed to in writing, software\r
+    distributed under the License is distributed on an "AS IS" BASIS,\r
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+    See the License for the specific language governing permissions and\r
+    limitations under the License.\r
+*/\r
+\r
+/**\r
+ * @file    osal.c\r
+ * @brief   OSAL module code.\r
+ *\r
+ * @addtogroup OSAL\r
+ * @{\r
+ */\r
+\r
+#include "osal.h"\r
+#include "osal_vt.h"\r
+\r
+/*===========================================================================*/\r
+/* Module local definitions.                                                 */\r
+/*===========================================================================*/\r
+\r
+/*===========================================================================*/\r
+/* Module exported variables.                                                */\r
+/*===========================================================================*/\r
+\r
+/**\r
+ * @brief   Pointer to a halt error message.\r
+ * @note    The message is meant to be retrieved by the debugger after the\r
+ *          system halt caused by an unexpected error.\r
+ */\r
+const char *osal_halt_msg;\r
+\r
+/*===========================================================================*/\r
+/* Module local types.                                                       */\r
+/*===========================================================================*/\r
+\r
+/*===========================================================================*/\r
+/* Module local variables.                                                   */\r
+/*===========================================================================*/\r
+\r
+/*===========================================================================*/\r
+/* Module local functions.                                                   */\r
+/*===========================================================================*/\r
+\r
+static void callback_timeout(void *p) {\r
+  osalSysLockFromISR();\r
+  osalThreadResumeI((thread_reference_t *)p, MSG_TIMEOUT);\r
+  osalSysUnlockFromISR();\r
+}\r
+\r
+/*===========================================================================*/\r
+/* Module exported functions.                                                */\r
+/*===========================================================================*/\r
+\r
+/**\r
+ * @brief   OSAL module initialization.\r
+ *\r
+ * @api\r
+ */\r
+void osalInit(void) {\r
+\r
+  vtInit();\r
+\r
+  OSAL_INIT_HOOK();\r
+}\r
+\r
+/**\r
+ * @brief   System halt with error message.\r
+ *\r
+ * @param[in] reason    the halt message pointer\r
+ *\r
+ * @api\r
+ */\r
+#if !defined(__DOXYGEN__)\r
+__attribute__((weak, noreturn))\r
+#endif\r
+void osalSysHalt(const char *reason) {\r
+\r
+  osalSysDisable();\r
+  osal_halt_msg = reason;\r
+  while (true) {\r
+  }\r
+}\r
+\r
+/**\r
+ * @brief   Polled delay.\r
+ * @note    The real delay is always few cycles in excess of the specified\r
+ *          value.\r
+ *\r
+ * @param[in] cycles    number of cycles\r
+ *\r
+ * @xclass\r
+ */\r
+void osalSysPolledDelayX(rtcnt_t cycles) {\r
+\r
+  (void)cycles;\r
+}\r
+\r
+/**\r
+ * @brief   System timer handler.\r
+ * @details The handler is used for scheduling and Virtual Timers management.\r
+ *\r
+ * @iclass\r
+ */\r
+void osalOsTimerHandlerI(void) {\r
+\r
+  osalDbgCheckClassI();\r
+\r
+  vtDoTickI();\r
+}\r
+\r
+/**\r
+ * @brief   Checks if a reschedule is required and performs it.\r
+ * @note    I-Class functions invoked from thread context must not reschedule\r
+ *          by themselves, an explicit reschedule using this function is\r
+ *          required in this scenario.\r
+ * @note    Not implemented in this simplified OSAL.\r
+ *\r
+ * @sclass\r
+ */\r
+void osalOsRescheduleS(void) {\r
+\r
+}\r
+\r
+/**\r
+ * @brief   Current system time.\r
+ * @details Returns the number of system ticks since the @p osalInit()\r
+ *          invocation.\r
+ * @note    The counter can reach its maximum and then restart from zero.\r
+ * @note    This function can be called from any context but its atomicity\r
+ *          is not guaranteed on architectures whose word size is less than\r
+ *          @p systime_t size.\r
+ *\r
+ * @return              The system time in ticks.\r
+ *\r
+ * @xclass\r
+ */\r
+systime_t osalOsGetSystemTimeX(void) {\r
+\r
+  return vtlist.vt_systime;\r
+}\r
+\r
+/**\r
+ * @brief   Suspends the invoking thread for the specified time.\r
+ *\r
+ * @param[in] time      the delay in system ticks, the special values are\r
+ *                      handled as follow:\r
+ *                      - @a TIME_INFINITE is allowed but interpreted as a\r
+ *                        normal time specification.\r
+ *                      - @a TIME_IMMEDIATE this value is not allowed.\r
+ *                      .\r
+ *\r
+ * @sclass\r
+ */\r
+void osalThreadSleepS(sysinterval_t time) {\r
+  virtual_timer_t vt;\r
+  thread_reference_t tr;\r
+\r
+  tr = NULL;\r
+  vtSetI(&vt, time, callback_timeout, (void *)&tr);\r
+  osalThreadSuspendS(&tr);\r
+}\r
+\r
+/**\r
+ * @brief   Suspends the invoking thread for the specified time.\r
+ *\r
+ * @param[in] time      the delay in system ticks, the special values are\r
+ *                      handled as follow:\r
+ *                      - @a TIME_INFINITE is allowed but interpreted as a\r
+ *                        normal time specification.\r
+ *                      - @a TIME_IMMEDIATE this value is not allowed.\r
+ *                      .\r
+ *\r
+ * @api\r
+ */\r
+void osalThreadSleep(sysinterval_t time) {\r
+\r
+  osalSysLock();\r
+  osalThreadSleepS(time);\r
+  osalSysUnlock();\r
+}\r
+\r
+/**\r
+ * @brief   Sends the current thread sleeping and sets a reference variable.\r
+ * @note    This function must reschedule, it can only be called from thread\r
+ *          context.\r
+ *\r
+ * @param[in] trp       a pointer to a thread reference object\r
+ * @return              The wake up message.\r
+ *\r
+ * @sclass\r
+ */\r
+msg_t osalThreadSuspendS(thread_reference_t *trp) {\r
+  thread_t self = {MSG_WAIT};\r
+\r
+  osalDbgCheck(trp != NULL);\r
+\r
+  *trp = &self;\r
+  while (self.message == MSG_WAIT) {\r
+    osalSysUnlock();\r
+    /* A state-changing interrupt could occur here and cause the loop to\r
+       terminate, an hook macro is executed while waiting.*/\r
+    OSAL_IDLE_HOOK();\r
+    osalSysLock();\r
+  }\r
+\r
+  return self.message;\r
+}\r
+\r
+/**\r
+ * @brief   Sends the current thread sleeping and sets a reference variable.\r
+ * @note    This function must reschedule, it can only be called from thread\r
+ *          context.\r
+ *\r
+ * @param[in] trp       a pointer to a thread reference object\r
+ * @param[in] timeout   the timeout in system ticks, the special values are\r
+ *                      handled as follow:\r
+ *                      - @a TIME_INFINITE the thread enters an infinite sleep\r
+ *                        state.\r
+ *                      - @a TIME_IMMEDIATE the thread is not enqueued and\r
+ *                        the function returns @p MSG_TIMEOUT as if a timeout\r
+ *                        occurred.\r
+ *                      .\r
+ * @return              The wake up message.\r
+ * @retval MSG_TIMEOUT  if the operation timed out.\r
+ *\r
+ * @sclass\r
+ */\r
+msg_t osalThreadSuspendTimeoutS(thread_reference_t *trp, sysinterval_t timeout) {\r
+  msg_t msg;\r
+  virtual_timer_t vt;\r
+\r
+  osalDbgCheck(trp != NULL);\r
+\r
+  if (TIME_INFINITE == timeout)\r
+   return osalThreadSuspendS(trp);\r
+\r
+  vtSetI(&vt, timeout, callback_timeout, (void *)trp);\r
+  msg = osalThreadSuspendS(trp);\r
+  if (vtIsArmedI(&vt))\r
+    vtResetI(&vt);\r
+\r
+  return msg;\r
+}\r
+\r
+/**\r
+ * @brief   Wakes up a thread waiting on a thread reference object.\r
+ * @note    This function must not reschedule because it can be called from\r
+ *          ISR context.\r
+ *\r
+ * @param[in] trp       a pointer to a thread reference object\r
+ * @param[in] msg       the message code\r
+ *\r
+ * @iclass\r
+ */\r
+void osalThreadResumeI(thread_reference_t *trp, msg_t msg) {\r
+\r
+  osalDbgCheck(trp != NULL);\r
+\r
+  if (*trp != NULL) {\r
+    (*trp)->message = msg;\r
+    *trp = NULL;\r
+  }\r
+}\r
+\r
+/**\r
+ * @brief   Wakes up a thread waiting on a thread reference object.\r
+ * @note    This function must reschedule, it can only be called from thread\r
+ *          context.\r
+ *\r
+ * @param[in] trp       a pointer to a thread reference object\r
+ * @param[in] msg       the message code\r
+ *\r
+ * @iclass\r
+ */\r
+void osalThreadResumeS(thread_reference_t *trp, msg_t msg) {\r
+\r
+  osalDbgCheck(trp != NULL);\r
+\r
+  if (*trp != NULL) {\r
+    (*trp)->message = msg;\r
+    *trp = NULL;\r
+  }\r
+}\r
+\r
+/**\r
+ * @brief   Enqueues the caller thread.\r
+ * @details The caller thread is enqueued and put to sleep until it is\r
+ *          dequeued or the specified timeouts expires.\r
+ *\r
+ * @param[in] tqp       pointer to the threads queue object\r
+ * @param[in] timeout   the timeout in system ticks, the special values are\r
+ *                      handled as follow:\r
+ *                      - @a TIME_INFINITE the thread enters an infinite sleep\r
+ *                        state.\r
+ *                      - @a TIME_IMMEDIATE the thread is not enqueued and\r
+ *                        the function returns @p MSG_TIMEOUT as if a timeout\r
+ *                        occurred.\r
+ *                      .\r
+ * @return              The message from @p osalQueueWakeupOneI() or\r
+ *                      @p osalQueueWakeupAllI() functions.\r
+ * @retval MSG_TIMEOUT  if the thread has not been dequeued within the\r
+ *                      specified timeout or if the function has been\r
+ *                      invoked with @p TIME_IMMEDIATE as timeout\r
+ *                      specification.\r
+ *\r
+ * @sclass\r
+ */\r
+msg_t osalThreadEnqueueTimeoutS(threads_queue_t *tqp, sysinterval_t timeout) {\r
+  msg_t msg;\r
+  virtual_timer_t vt;\r
+\r
+  osalDbgCheck(tqp != NULL);\r
+\r
+  if (TIME_IMMEDIATE == timeout)\r
+    return MSG_TIMEOUT;\r
+\r
+  tqp->tr = NULL;\r
+\r
+  if (TIME_INFINITE == timeout)\r
+   return osalThreadSuspendS(&tqp->tr);\r
+\r
+  vtSetI(&vt, timeout, callback_timeout, (void *)&tqp->tr);\r
+  msg = osalThreadSuspendS(&tqp->tr);\r
+  if (vtIsArmedI(&vt))\r
+    vtResetI(&vt);\r
+\r
+  return msg;\r
+}\r
+\r
+/**\r
+ * @brief   Dequeues and wakes up one thread from the queue, if any.\r
+ *\r
+ * @param[in] tqp       pointer to the threads queue object\r
+ * @param[in] msg       the message code\r
+ *\r
+ * @iclass\r
+ */\r
+void osalThreadDequeueNextI(threads_queue_t *tqp, msg_t msg) {\r
+\r
+  osalDbgCheck(tqp != NULL);\r
+\r
+  osalThreadResumeI(&tqp->tr, msg);\r
+}\r
+\r
+/**\r
+ * @brief   Dequeues and wakes up all threads from the queue.\r
+ *\r
+ * @param[in] tqp       pointer to the threads queue object\r
+ * @param[in] msg       the message code\r
+ *\r
+ * @iclass\r
+ */\r
+void osalThreadDequeueAllI(threads_queue_t *tqp, msg_t msg) {\r
+\r
+  osalDbgCheck(tqp != NULL);\r
+\r
+  osalThreadResumeI(&tqp->tr, msg);\r
+}\r
+\r
+/**\r
+ * @brief   Add flags to an event source object.\r
+ *\r
+ * @param[in] esp       pointer to the event flags object\r
+ * @param[in] flags     flags to be ORed to the flags mask\r
+ *\r
+ * @iclass\r
+ */\r
+void osalEventBroadcastFlagsI(event_source_t *esp, eventflags_t flags) {\r
+\r
+  osalDbgCheck(esp != NULL);\r
+\r
+  esp->flags |= flags;\r
+  if (esp->cb != NULL) {\r
+    esp->cb(esp);\r
+  }\r
+}\r
+\r
+/**\r
+ * @brief   Add flags to an event source object.\r
+ *\r
+ * @param[in] esp       pointer to the event flags object\r
+ * @param[in] flags     flags to be ORed to the flags mask\r
+ *\r
+ * @iclass\r
+ */\r
+void osalEventBroadcastFlags(event_source_t *esp, eventflags_t flags) {\r
+\r
+  osalDbgCheck(esp != NULL);\r
+\r
+  osalSysLock();\r
+  osalEventBroadcastFlagsI(esp, flags);\r
+  osalSysUnlock();\r
+}\r
+\r
+/**\r
+ * @brief   Event callback setup.\r
+ * @note    The callback is invoked from ISR context and can\r
+ *          only invoke I-Class functions. The callback is meant\r
+ *          to wakeup the task that will handle the event by\r
+ *          calling @p osalEventGetAndClearFlagsI().\r
+ * @note    This function is not part of the OSAL API and is provided\r
+ *          exclusively as an example and for convenience.\r
+ *\r
+ * @param[in] esp       pointer to the event flags object\r
+ * @param[in] cb        pointer to the callback function\r
+ * @param[in] param     parameter to be passed to the callback function\r
+ *\r
+ * @api\r
+ */\r
+void osalEventSetCallback(event_source_t *esp,\r
+                          eventcallback_t cb,\r
+                          void *param) {\r
+\r
+  osalDbgCheck(esp != NULL);\r
+\r
+  esp->cb    = cb;\r
+  esp->param = param;\r
+}\r
+\r
+/**\r
+ * @brief   Locks the specified mutex.\r
+ * @post    The mutex is locked and inserted in the per-thread stack of owned\r
+ *          mutexes.\r
+ *\r
+ * @param[in,out] mp    pointer to the @p mutex_t object\r
+ *\r
+ * @api\r
+ */\r
+void osalMutexLock(mutex_t *mp) {\r
+\r
+  osalDbgCheck(mp != NULL);\r
+\r
+  *mp = 1;\r
+}\r
+\r
+/**\r
+ * @brief   Unlocks the specified mutex.\r
+ * @note    The HAL guarantees to release mutex in reverse lock order. The\r
+ *          mutex being unlocked is guaranteed to be the last locked mutex\r
+ *          by the invoking thread.\r
+ *          The implementation can rely on this behavior and eventually\r
+ *          ignore the @p mp parameter which is supplied in order to support\r
+ *          those OSes not supporting a stack of the owned mutexes.\r
+ *\r
+ * @param[in,out] mp    pointer to the @p mutex_t object\r
+ *\r
+ * @api\r
+ */\r
+void osalMutexUnlock(mutex_t *mp) {\r
+\r
+  osalDbgCheck(mp != NULL);\r
+\r
+  *mp = 0;\r
+}\r
+\r
+/** @} */\r
diff --git a/source/osal.h b/source/osal.h
new file mode 100644 (file)
index 0000000..30e1592
--- /dev/null
@@ -0,0 +1,754 @@
+/*\r
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio\r
+\r
+    Licensed under the Apache License, Version 2.0 (the "License");\r
+    you may not use this file except in compliance with the License.\r
+    You may obtain a copy of the License at\r
+\r
+        http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+    Unless required by applicable law or agreed to in writing, software\r
+    distributed under the License is distributed on an "AS IS" BASIS,\r
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+    See the License for the specific language governing permissions and\r
+    limitations under the License.\r
+*/\r
+\r
+/**\r
+ * @file    osal.h\r
+ * @brief   OSAL module header.\r
+ *\r
+ * @addtogroup OSAL\r
+ * @{\r
+ */\r
+\r
+#ifndef OSAL_H\r
+#define OSAL_H\r
+\r
+#include <stddef.h>\r
+#include <stdint.h>\r
+#include <stdbool.h>\r
+\r
+#include "cmparams.h"\r
+\r
+#include "osalconf.h"\r
+\r
+/*===========================================================================*/\r
+/* Module constants.                                                         */\r
+/*===========================================================================*/\r
+\r
+/**\r
+ * @name    Common constants\r
+ * @{\r
+ */\r
+#if !defined(FALSE) || defined(__DOXYGEN__)\r
+#define FALSE                               0\r
+#endif\r
+\r
+#if !defined(TRUE) || defined(__DOXYGEN__)\r
+#define TRUE                                1\r
+#endif\r
+\r
+#define OSAL_SUCCESS                        false\r
+#define OSAL_FAILED                         true\r
+/** @} */\r
+\r
+/**\r
+ * @name    Messages\r
+ * @{\r
+ */\r
+#define MSG_OK                              (msg_t)0\r
+#define MSG_RESET                           (msg_t)-1\r
+#define MSG_TIMEOUT                         (msg_t)-2\r
+#define MSG_WAIT                            (msg_t)-10\r
+/** @} */\r
+\r
+/**\r
+ * @name    Special time constants\r
+ * @{\r
+ */\r
+#define TIME_IMMEDIATE                      ((sysinterval_t)0)\r
+#define TIME_INFINITE                       ((sysinterval_t)-1)\r
+/** @} */\r
+\r
+/**\r
+ * @name    Systick modes.\r
+ * @{\r
+ */\r
+#define OSAL_ST_MODE_NONE                   0\r
+#define OSAL_ST_MODE_PERIODIC               1\r
+#define OSAL_ST_MODE_FREERUNNING            2\r
+/** @} */\r
+\r
+/**\r
+ * @name    Systick parameters.\r
+ * @{\r
+ */\r
+/**\r
+ * @brief   Size in bits of the @p systick_t type.\r
+ */\r
+#define OSAL_ST_RESOLUTION                  32\r
+\r
+/**\r
+ * @brief   Systick mode required by the underlying OS.\r
+ */\r
+#define OSAL_ST_MODE                        OSAL_ST_MODE_NONE\r
+/** @} */\r
+\r
+/**\r
+ * @name    IRQ-related constants\r
+ * @{\r
+ */\r
+/**\r
+ * @brief   Total priority levels.\r
+ */\r
+#define OSAL_IRQ_PRIORITY_LEVELS            (1U << CORTEX_PRIORITY_BITS)\r
+\r
+/**\r
+ * @brief   Highest IRQ priority for HAL drivers.\r
+ */\r
+#if (CORTEX_MODEL == 0) || defined(__DOXYGEN__)\r
+#define OSAL_IRQ_MAXIMUM_PRIORITY           0\r
+#else\r
+#define OSAL_IRQ_MAXIMUM_PRIORITY           1\r
+#endif\r
+\r
+/**\r
+ * @brief   Converts from numeric priority to BASEPRI register value.\r
+ */\r
+#define OSAL_BASEPRI(priority)              ((priority) << (8U - CORTEX_PRIORITY_BITS))\r
+/** @} */\r
+\r
+/*===========================================================================*/\r
+/* Module pre-compile time settings.                                         */\r
+/*===========================================================================*/\r
+\r
+/**\r
+ * @brief   Frequency in Hertz of the system tick.\r
+ */\r
+#if !defined(OSAL_ST_FREQUENCY) || defined(__DOXYGEN__)\r
+#define OSAL_ST_FREQUENCY                   1000\r
+#endif\r
+\r
+/**\r
+ * @brief   Enables OSAL assertions.\r
+ */\r
+#if !defined(OSAL_DBG_ENABLE_ASSERTS) || defined(__DOXYGEN__)\r
+#define OSAL_DBG_ENABLE_ASSERTS             FALSE\r
+#endif\r
+\r
+/**\r
+ * @brief   Enables OSAL functions parameters checks.\r
+ */\r
+#if !defined(OSAL_DBG_ENABLE_CHECKS) || defined(__DOXYGEN__)\r
+#define OSAL_DBG_ENABLE_CHECKS              FALSE\r
+#endif\r
+\r
+/**\r
+ * @brief   OSAL initialization hook.\r
+ */\r
+#if !defined(OSAL_INIT_HOOK) || defined(__DOXYGEN__)\r
+#define OSAL_INIT_HOOK()\r
+#endif\r
+\r
+/**\r
+ * @brief   Idle loop hook macro.\r
+ */\r
+#if !defined(OSAL_IDLE_HOOK) || defined(__DOXYGEN__)\r
+#define OSAL_IDLE_HOOK()\r
+#endif\r
+\r
+/*===========================================================================*/\r
+/* Derived constants and error checks.                                       */\r
+/*===========================================================================*/\r
+\r
+/*===========================================================================*/\r
+/* Module data structures and types.                                         */\r
+/*===========================================================================*/\r
+\r
+/**\r
+ * @brief   Type of a system status word.\r
+ */\r
+typedef uint32_t syssts_t;\r
+\r
+/**\r
+ * @brief   Type of a message.\r
+ */\r
+typedef int32_t msg_t;\r
+\r
+/**\r
+ * @brief   Type of system time counter.\r
+ */\r
+typedef uint32_t systime_t;\r
+\r
+/**\r
+ * @brief   Type of system time interval.\r
+ */\r
+typedef uint32_t sysinterval_t;\r
+\r
+/**\r
+ * @brief   Type of realtime counter.\r
+ */\r
+typedef uint32_t rtcnt_t;\r
+\r
+/**\r
+ * @brief   Type of a thread.\r
+ * @note    The content of this structure is not part of the API and should\r
+ *          not be relied upon. Implementers may define this structure in\r
+ *          an entirely different way.\r
+ */\r
+typedef struct {\r
+  volatile msg_t        message;\r
+} thread_t;\r
+\r
+/**\r
+ * @brief   Type of a thread reference.\r
+ */\r
+typedef thread_t * thread_reference_t;\r
+\r
+/**\r
+ * @brief   Type of an event flags mask.\r
+ */\r
+typedef uint32_t eventflags_t;\r
+\r
+/**\r
+ * @brief   Type of an event flags object.\r
+ * @note    The content of this structure is not part of the API and should\r
+ *          not be relied upon. Implementers may define this structure in\r
+ *          an entirely different way.\r
+ * @note    Retrieval and clearing of the flags are not defined in this\r
+ *          API and are implementation-dependent.\r
+ */\r
+typedef struct event_source event_source_t;\r
+\r
+/**\r
+ * @brief   Type of an event source callback.\r
+ * @note    This type is not part of the OSAL API and is provided\r
+ *          exclusively as an example and for convenience.\r
+ */\r
+typedef void (*eventcallback_t)(event_source_t *esp);\r
+\r
+/**\r
+ * @brief   Events source object.\r
+ * @note    The content of this structure is not part of the API and should\r
+ *          not be relied upon. Implementers may define this structure in\r
+ *          an entirely different way.\r
+ * @note    Retrieval and clearing of the flags are not defined in this\r
+ *          API and are implementation-dependent.\r
+ */\r
+struct event_source {\r
+  volatile eventflags_t flags;      /**< @brief Stored event flags.         */\r
+  eventcallback_t       cb;         /**< @brief Event source callback.      */\r
+  void                  *param;     /**< @brief User defined field.         */\r
+};\r
+\r
+/**\r
+ * @brief   Type of a mutex.\r
+ * @note    If the OS does not support mutexes or there is no OS then them\r
+ *          mechanism can be simulated.\r
+ */\r
+typedef uint32_t mutex_t;\r
+\r
+/**\r
+ * @brief   Type of a thread queue.\r
+ * @details A thread queue is a queue of sleeping threads, queued threads\r
+ *          can be dequeued one at time or all together.\r
+ * @note    If the OSAL is implemented on a bare metal machine without RTOS\r
+ *          then the queue can be implemented as a single thread reference.\r
+ */\r
+typedef struct {\r
+  thread_reference_t    tr;\r
+} threads_queue_t;\r
+\r
+/*===========================================================================*/\r
+/* Module macros.                                                            */\r
+/*===========================================================================*/\r
+\r
+/**\r
+ * @name    Debug related macros\r
+ * @{\r
+ */\r
+/**\r
+ * @brief   Condition assertion.\r
+ * @details If the condition check fails then the OSAL panics with a\r
+ *          message and halts.\r
+ * @note    The condition is tested only if the @p OSAL_ENABLE_ASSERTIONS\r
+ *          switch is enabled.\r
+ * @note    The remark string is not currently used except for putting a\r
+ *          comment in the code about the assertion.\r
+ *\r
+ * @param[in] c         the condition to be verified to be true\r
+ * @param[in] remark    a remark string\r
+ *\r
+ * @api\r
+ */\r
+#define osalDbgAssert(c, remark) do {                                       \\r
+  /*lint -save -e506 -e774 [2.1, 14.3] Can be a constant by design.*/       \\r
+  if (OSAL_DBG_ENABLE_ASSERTS != FALSE) {                                   \\r
+    if (!(c)) {                                                             \\r
+  /*lint -restore*/                                                         \\r
+      osalSysHalt(__func__);                                                \\r
+    }                                                                       \\r
+  }                                                                         \\r
+} while (false)\r
+\r
+/**\r
+ * @brief   Function parameters check.\r
+ * @details If the condition check fails then the OSAL panics and halts.\r
+ * @note    The condition is tested only if the @p OSAL_ENABLE_CHECKS switch\r
+ *          is enabled.\r
+ *\r
+ * @param[in] c         the condition to be verified to be true\r
+ *\r
+ * @api\r
+ */\r
+#define osalDbgCheck(c) do {                                                \\r
+  /*lint -save -e506 -e774 [2.1, 14.3] Can be a constant by design.*/       \\r
+  if (OSAL_DBG_ENABLE_CHECKS != FALSE) {                                    \\r
+    if (!(c)) {                                                             \\r
+  /*lint -restore*/                                                         \\r
+      osalSysHalt(__func__);                                                \\r
+    }                                                                       \\r
+  }                                                                         \\r
+} while (false)\r
+\r
+/**\r
+ * @brief   I-Class state check.\r
+ * @note    Implementation is optional.\r
+ */\r
+#define osalDbgCheckClassI()\r
+\r
+/**\r
+ * @brief   S-Class state check.\r
+ * @note    Implementation is optional.\r
+ */\r
+#define osalDbgCheckClassS()\r
+/** @} */\r
+\r
+/**\r
+ * @name    IRQ service routines wrappers\r
+ * @{\r
+ */\r
+/**\r
+ * @brief   Priority level verification macro.\r
+ */\r
+#define OSAL_IRQ_IS_VALID_PRIORITY(n)                                       \\r
+  (((n) >= OSAL_IRQ_MAXIMUM_PRIORITY) && ((n) < OSAL_IRQ_PRIORITY_LEVELS))\r
+\r
+/**\r
+ * @brief   IRQ prologue code.\r
+ * @details This macro must be inserted at the start of all IRQ handlers.\r
+ */\r
+#define OSAL_IRQ_PROLOGUE()\r
+\r
+/**\r
+ * @brief   IRQ epilogue code.\r
+ * @details This macro must be inserted at the end of all IRQ handlers.\r
+ */\r
+#define OSAL_IRQ_EPILOGUE()\r
+\r
+/**\r
+ * @brief   IRQ handler function declaration.\r
+ * @details This macro hides the details of an ISR function declaration.\r
+ *\r
+ * @param[in] id        a vector name as defined in @p vectors.s\r
+ */\r
+#define OSAL_IRQ_HANDLER(id) void id(void)\r
+/** @} */\r
+\r
+/**\r
+ * @name    Time conversion utilities\r
+ * @{\r
+ */\r
+/**\r
+ * @brief   Seconds to system ticks.\r
+ * @details Converts from seconds to system ticks number.\r
+ * @note    The result is rounded upward to the next tick boundary.\r
+ *\r
+ * @param[in] secs      number of seconds\r
+ * @return              The number of ticks.\r
+ *\r
+ * @api\r
+ */\r
+#define OSAL_S2I(secs)                                                      \\r
+  ((sysinterval_t)((uint32_t)(secs) * (uint32_t)OSAL_ST_FREQUENCY))\r
+\r
+/**\r
+ * @brief   Milliseconds to system ticks.\r
+ * @details Converts from milliseconds to system ticks number.\r
+ * @note    The result is rounded upward to the next tick boundary.\r
+ *\r
+ * @param[in] msecs     number of milliseconds\r
+ * @return              The number of ticks.\r
+ *\r
+ * @api\r
+ */\r
+#define OSAL_MS2I(msecs)                                                    \\r
+  ((sysinterval_t)((((((uint32_t)(msecs)) *                                 \\r
+                  ((uint32_t)OSAL_ST_FREQUENCY)) - 1UL) / 1000UL) + 1UL))\r
+\r
+/**\r
+ * @brief   Microseconds to system ticks.\r
+ * @details Converts from microseconds to system ticks number.\r
+ * @note    The result is rounded upward to the next tick boundary.\r
+ *\r
+ * @param[in] usecs     number of microseconds\r
+ * @return              The number of ticks.\r
+ *\r
+ * @api\r
+ */\r
+#define OSAL_US2I(usecs)                                                    \\r
+  ((sysinterval_t)((((((uint32_t)(usecs)) *                                 \\r
+                  ((uint32_t)OSAL_ST_FREQUENCY)) - 1UL) / 1000000UL) + 1UL))\r
+/** @} */\r
+\r
+/**\r
+ * @name    Time conversion utilities for the realtime counter\r
+ * @{\r
+ */\r
+/**\r
+ * @brief   Seconds to realtime counter.\r
+ * @details Converts from seconds to realtime counter cycles.\r
+ * @note    The macro assumes that @p freq >= @p 1.\r
+ *\r
+ * @param[in] freq      clock frequency, in Hz, of the realtime counter\r
+ * @param[in] sec       number of seconds\r
+ * @return              The number of cycles.\r
+ *\r
+ * @api\r
+ */\r
+#define OSAL_S2RTC(freq, sec) ((freq) * (sec))\r
+\r
+/**\r
+ * @brief   Milliseconds to realtime counter.\r
+ * @details Converts from milliseconds to realtime counter cycles.\r
+ * @note    The result is rounded upward to the next millisecond boundary.\r
+ * @note    The macro assumes that @p freq >= @p 1000.\r
+ *\r
+ * @param[in] freq      clock frequency, in Hz, of the realtime counter\r
+ * @param[in] msec      number of milliseconds\r
+ * @return              The number of cycles.\r
+ *\r
+ * @api\r
+ */\r
+#define OSAL_MS2RTC(freq, msec) (rtcnt_t)((((freq) + 999UL) / 1000UL) * (msec))\r
+\r
+/**\r
+ * @brief   Microseconds to realtime counter.\r
+ * @details Converts from microseconds to realtime counter cycles.\r
+ * @note    The result is rounded upward to the next microsecond boundary.\r
+ * @note    The macro assumes that @p freq >= @p 1000000.\r
+ *\r
+ * @param[in] freq      clock frequency, in Hz, of the realtime counter\r
+ * @param[in] usec      number of microseconds\r
+ * @return              The number of cycles.\r
+ *\r
+ * @api\r
+ */\r
+#define OSAL_US2RTC(freq, usec) (rtcnt_t)((((freq) + 999999UL) / 1000000UL) * (usec))\r
+/** @} */\r
+\r
+/**\r
+ * @name    Sleep macros using absolute time\r
+ * @{\r
+ */\r
+/**\r
+ * @brief   Delays the invoking thread for the specified number of seconds.\r
+ * @note    The specified time is rounded up to a value allowed by the real\r
+ *          system tick clock.\r
+ * @note    The maximum specifiable value is implementation dependent.\r
+ *\r
+ * @param[in] secs      time in seconds, must be different from zero\r
+ *\r
+ * @api\r
+ */\r
+#define osalThreadSleepSeconds(secs) osalThreadSleep(OSAL_S2I(secs))\r
+\r
+/**\r
+ * @brief   Delays the invoking thread for the specified number of\r
+ *          milliseconds.\r
+ * @note    The specified time is rounded up to a value allowed by the real\r
+ *          system tick clock.\r
+ * @note    The maximum specifiable value is implementation dependent.\r
+ *\r
+ * @param[in] msecs     time in milliseconds, must be different from zero\r
+ *\r
+ * @api\r
+ */\r
+#define osalThreadSleepMilliseconds(msecs) osalThreadSleep(OSAL_MS2I(msecs))\r
+\r
+/**\r
+ * @brief   Delays the invoking thread for the specified number of\r
+ *          microseconds.\r
+ * @note    The specified time is rounded up to a value allowed by the real\r
+ *          system tick clock.\r
+ * @note    The maximum specifiable value is implementation dependent.\r
+ *\r
+ * @param[in] usecs     time in microseconds, must be different from zero\r
+ *\r
+ * @api\r
+ */\r
+#define osalThreadSleepMicroseconds(usecs) osalThreadSleep(OSAL_US2I(usecs))\r
+/** @} */\r
+\r
+/*===========================================================================*/\r
+/* External declarations.                                                    */\r
+/*===========================================================================*/\r
+\r
+extern const char *osal_halt_msg;\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+  void osalInit(void);\r
+  void osalSysHalt(const char *reason);\r
+  void osalSysPolledDelayX(rtcnt_t cycles);\r
+  void osalOsTimerHandlerI(void);\r
+  void osalOsRescheduleS(void);\r
+  systime_t osalOsGetSystemTimeX(void);\r
+  void osalThreadSleepS(sysinterval_t time);\r
+  void osalThreadSleep(sysinterval_t time);\r
+  msg_t osalThreadSuspendS(thread_reference_t *trp);\r
+  msg_t osalThreadSuspendTimeoutS(thread_reference_t *trp, sysinterval_t timeout);\r
+  void osalThreadResumeI(thread_reference_t *trp, msg_t msg);\r
+  void osalThreadResumeS(thread_reference_t *trp, msg_t msg);\r
+  msg_t osalThreadEnqueueTimeoutS(threads_queue_t *tqp, sysinterval_t timeout);\r
+  void osalThreadDequeueNextI(threads_queue_t *tqp, msg_t msg);\r
+  void osalThreadDequeueAllI(threads_queue_t *tqp, msg_t msg);\r
+  void osalEventBroadcastFlagsI(event_source_t *esp, eventflags_t flags);\r
+  void osalEventBroadcastFlags(event_source_t *esp, eventflags_t flags);\r
+  void osalEventSetCallback(event_source_t *esp,\r
+                            eventcallback_t cb,\r
+                            void *param);\r
+  void osalMutexLock(mutex_t *mp);\r
+  void osalMutexUnlock(mutex_t *mp);\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+/*===========================================================================*/\r
+/* Module inline functions.                                                  */\r
+/*===========================================================================*/\r
+\r
+/**\r
+ * @brief   Disables interrupts globally.\r
+ *\r
+ * @special\r
+ */\r
+static inline void osalSysDisable(void) {\r
+\r
+  __disable_irq();\r
+}\r
+\r
+/**\r
+ * @brief   Enables interrupts globally.\r
+ *\r
+ * @special\r
+ */\r
+static inline void osalSysEnable(void) {\r
+\r
+  __enable_irq();\r
+}\r
+\r
+/**\r
+ * @brief   Enters a critical zone from thread context.\r
+ * @note    This function cannot be used for reentrant critical zones.\r
+ *\r
+ * @special\r
+ */\r
+static inline void osalSysLock(void) {\r
+\r
+#if CORTEX_MODEL == 0\r
+  __disable_irq();\r
+#else\r
+  __set_BASEPRI(OSAL_BASEPRI(OSAL_IRQ_MAXIMUM_PRIORITY));\r
+#endif\r
+}\r
+\r
+/**\r
+ * @brief   Leaves a critical zone from thread context.\r
+ * @note    This function cannot be used for reentrant critical zones.\r
+ *\r
+ * @special\r
+ */\r
+static inline void osalSysUnlock(void) {\r
+\r
+#if CORTEX_MODEL == 0\r
+  __enable_irq();\r
+#else\r
+  __set_BASEPRI(0);\r
+#endif\r
+}\r
+\r
+/**\r
+ * @brief   Enters a critical zone from ISR context.\r
+ * @note    This function cannot be used for reentrant critical zones.\r
+ *\r
+ * @special\r
+ */\r
+static inline void osalSysLockFromISR(void) {\r
+\r
+#if CORTEX_MODEL == 0\r
+  __disable_irq();\r
+#else\r
+  __set_BASEPRI(OSAL_BASEPRI(OSAL_IRQ_MAXIMUM_PRIORITY));\r
+#endif\r
+}\r
+\r
+/**\r
+ * @brief   Leaves a critical zone from ISR context.\r
+ * @note    This function cannot be used for reentrant critical zones.\r
+ *\r
+ * @special\r
+ */\r
+static inline void osalSysUnlockFromISR(void) {\r
+\r
+#if CORTEX_MODEL == 0\r
+  __enable_irq();\r
+#else\r
+  __set_BASEPRI(0);\r
+#endif\r
+}\r
+\r
+/**\r
+ * @brief   Returns the execution status and enters a critical zone.\r
+ * @details This functions enters into a critical zone and can be called\r
+ *          from any context. Because its flexibility it is less efficient\r
+ *          than @p chSysLock() which is preferable when the calling context\r
+ *          is known.\r
+ * @post    The system is in a critical zone.\r
+ *\r
+ * @return              The previous system status, the encoding of this\r
+ *                      status word is architecture-dependent and opaque.\r
+ *\r
+ * @xclass\r
+ */\r
+static inline syssts_t osalSysGetStatusAndLockX(void) {\r
+  syssts_t sts;\r
+\r
+#if CORTEX_MODEL == 0\r
+  sts = (syssts_t)__get_PRIMASK();\r
+  __disable_irq();\r
+#else\r
+  sts = (syssts_t)__get_BASEPRI();\r
+  __set_BASEPRI(OSAL_BASEPRI(OSAL_IRQ_MAXIMUM_PRIORITY));\r
+#endif\r
+  return sts;\r
+}\r
+\r
+/**\r
+ * @brief   Restores the specified execution status and leaves a critical zone.\r
+ * @note    A call to @p chSchRescheduleS() is automatically performed\r
+ *          if exiting the critical zone and if not in ISR context.\r
+ *\r
+ * @param[in] sts       the system status to be restored.\r
+ *\r
+ * @xclass\r
+ */\r
+static inline void osalSysRestoreStatusX(syssts_t sts) {\r
+\r
+#if CORTEX_MODEL == 0\r
+  if ((sts & (syssts_t)1) == (syssts_t)0) {\r
+    __enable_irq();\r
+  }\r
+#else\r
+  __set_BASEPRI(sts);\r
+#endif\r
+}\r
+\r
+/**\r
+ * @brief   Adds an interval to a system time returning a system time.\r
+ *\r
+ * @param[in] systime   base system time\r
+ * @param[in] interval  interval to be added\r
+ * @return              The new system time.\r
+ *\r
+ * @xclass\r
+ */\r
+static inline systime_t osalTimeAddX(systime_t systime,\r
+                                     sysinterval_t interval) {\r
+\r
+  return systime + (systime_t)interval;\r
+}\r
+\r
+/**\r
+ * @brief   Subtracts two system times returning an interval.\r
+ *\r
+ * @param[in] start     first system time\r
+ * @param[in] end       second system time\r
+ * @return              The interval representing the time difference.\r
+ *\r
+ * @xclass\r
+ */\r
+static inline sysinterval_t osalTimeDiffX(systime_t start, systime_t end) {\r
+\r
+  return (sysinterval_t)((systime_t)(end - start));\r
+}\r
+\r
+/**\r
+ * @brief   Checks if the specified time is within the specified time window.\r
+ * @note    When start==end then the function returns always false because the\r
+ *          time window has zero size.\r
+ * @note    This function can be called from any context.\r
+ *\r
+ * @param[in] time      the time to be verified\r
+ * @param[in] start     the start of the time window (inclusive)\r
+ * @param[in] end       the end of the time window (non inclusive)\r
+ * @retval true         current time within the specified time window.\r
+ * @retval false        current time not within the specified time window.\r
+ *\r
+ * @xclass\r
+ */\r
+static inline bool osalTimeIsInRangeX(systime_t time,\r
+                                      systime_t start,\r
+                                      systime_t end) {\r
+\r
+  return (bool)((systime_t)((systime_t)time - (systime_t)start) <\r
+                (systime_t)((systime_t)end - (systime_t)start));\r
+}\r
+\r
+/**\r
+ * @brief   Initializes a threads queue object.\r
+ *\r
+ * @param[out] tqp      pointer to the threads queue object\r
+ *\r
+ * @init\r
+ */\r
+static inline void osalThreadQueueObjectInit(threads_queue_t *tqp) {\r
+\r
+  osalDbgCheck(tqp != NULL);\r
+}\r
+\r
+/**\r
+ * @brief   Initializes an event source object.\r
+ *\r
+ * @param[out] esp      pointer to the event source object\r
+ *\r
+ * @init\r
+ */\r
+static inline void osalEventObjectInit(event_source_t *esp) {\r
+\r
+  osalDbgCheck(esp != NULL);\r
+\r
+  esp->flags = (eventflags_t)0;\r
+  esp->cb    = NULL;\r
+  esp->param = NULL;\r
+}\r
+\r
+/**\r
+ * @brief   Initializes s @p mutex_t object.\r
+ *\r
+ * @param[out] mp       pointer to the @p mutex_t object\r
+ *\r
+ * @init\r
+ */\r
+static inline void osalMutexObjectInit(mutex_t *mp) {\r
+\r
+  osalDbgCheck(mp != NULL);\r
+\r
+  *mp = 0;\r
+}\r
+\r
+#endif /* OSAL_H */\r
+\r
+/** @} */\r