ChibiOS_*/
build
-.dep
+.*
+++ /dev/null
-#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;
-}
+++ /dev/null
-void g2048_init();
-int g2048_loop();
-
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
+++ /dev/null
-/**
- * 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);
-}
-
+++ /dev/null
-/**
- * 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_
-
+++ /dev/null
-/**
- * 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);
-}
-
+++ /dev/null
-/**
- * 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_
-
+++ /dev/null
-#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;
-}
-
+++ /dev/null
-#ifndef FLAPBIRD_H_
-#define FLAPBIRD_H_
-
-void flapbird_init();
-int flapbird_loop();
-
-#endif // FLAPBIRD_H_
-
+++ /dev/null
-/**
- * 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;
-}
-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"
+++ /dev/null
-/*\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
+++ /dev/null
-/*\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
--- /dev/null
+#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;
+}
--- /dev/null
+void g2048_init();
+int g2048_loop();
+
--- /dev/null
+/**
+ * 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);
+}
+
--- /dev/null
+/**
+ * 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_
+
--- /dev/null
+/**
+ * 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);
+}
+
--- /dev/null
+/**
+ * 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_
+
--- /dev/null
+#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;
+}
+
--- /dev/null
+#ifndef FLAPBIRD_H_
+#define FLAPBIRD_H_
+
+void flapbird_init();
+int flapbird_loop();
+
+#endif // FLAPBIRD_H_
+
--- /dev/null
+/**
+ * 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;
+}
--- /dev/null
+/*\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
--- /dev/null
+/*\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