Skip to content

Commit

Permalink
Merge pull request #10 from vladkorotnev/develop
Browse files Browse the repository at this point in the history
Release v3.5
  • Loading branch information
vladkorotnev authored Sep 2, 2024
2 parents 367da7e + 45cf58e commit 7cfebae
Show file tree
Hide file tree
Showing 69 changed files with 5,170 additions and 258 deletions.
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ WEATHER_API_KEY=\"your OpenWeatherMap API Key\"

# Wordnik configuration
WORDNIK_API_KEY=\"your Wordnik API key\"

# AquesTalk configuration
AQUESTALK_LICENSE_KEY=\"XXX-XXX-XXX\"
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ captures/
.env
/src/weather_icons
.vscode/
/lib/nonfree-aquestalk/aquestalk.h
/lib/nonfree-aquestalk/*.a
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ You can also read the quest I went through trying to get it to run "in real time

![](docs/img/widget/weather.gif)

* Weather Forecast

![](docs/img/widget/forecast.gif)

* Hourly Precipitation and Pressure charts

![](docs/img/widget/charts.gif)

* Weather Effect (raining and thunder on idle screen when rain/thunderstorm outside)

![](docs/img/widget/rain.gif)
Expand Down Expand Up @@ -120,6 +128,9 @@ You can also read the quest I went through trying to get it to run "in real time
* [Timbaland - Give It To Me](https://youtube.com/watch?v=RgoiSJ23cSc) also known as [Skibidi Toilet](https://youtu.be/6dMjCa0nqK0): [MIDI](helper/chimes/skibidi_toilet.mid), [MP3 Recording](docs/rec/skibidi.mp3)
* [PinocchioP - God-ish (神っぽいな)](https://www.youtube.com/watch?v=EHBFKhLUVig): [MIDI](helper/chimes/kamippoina.mid), [MP3 Recording](docs/rec/kamippoina.mp3)
* [KOTOKO - Re-sublimity](https://youtu.be/QXDwb2rueYM?t=65): [MIDI](helper/chimes/resublimity.mid), [MP3 Recording](docs/rec/re_sublimity.mp3) - simple piano-ish score, better cover TBD?
* [Calvin Harris - Acceptable In The 80s](https://youtu.be/dOV5WXISM24?t=14): [MIDI](helper/chimes/inthe80s.mid)
* [emon - shake it!](https://www.youtube.com/watch?v=WxexMGe83No): [MIDI](helper/chimes/shakeit.mid), [MP3 Recording](docs/rec/shakeit.mp3)
* [Omega - Én elmegyek](https://www.youtube.com/watch?v=L74IyC1N43M): [MIDI](helper/chimes/en_elmegyek.mid) (thanks [lemuel_producer](https://www.fiverr.com/lemuel_producer) for the help!)

## Creating your own melodies

Expand Down
Binary file added docs/img/widget/charts.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/widget/forecast.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/rec/shakeit.mp3
Binary file not shown.
8 changes: 8 additions & 0 deletions helper/aquestalk-detect.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from os.path import isfile
Import("env")

if isfile("./lib/nonfree-aquestalk/libaquestalk.a"):
print("Found a copy of AquesTalk")
env.Append(BUILD_FLAGS=["-LD:lib/nonfree-aquestalk", "-laquestalk", "-DLIBAQUESTALK_FOUND"])
else:
print("No AquesTalk library found")
Binary file added helper/chimes/en_elmegyek.mid
Binary file not shown.
Binary file added helper/chimes/inthe80s.mid
Binary file not shown.
Binary file added helper/chimes/shakeit.mid
Binary file not shown.
26 changes: 24 additions & 2 deletions helper/midi_to_chime.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,28 @@
mid = MidiFile(argv[1])
name = argv[2]

USE_TBL = True
NOTE_TBL = [
31, 33, 35, 37, 39, 41, 44, 46,
49, 52, 55, 58, 62, 65, 69, 73,
78, 82, 87, 93, 98, 104, 110, 117,
123, 131, 139, 147, 156, 165, 175, 185,
196, 208, 220, 233, 247, 262, 277, 294,
311, 330, 349, 370, 392, 415, 440, 466,
494, 523, 554, 587, 622, 659, 698, 740,
784, 831, 880, 932, 988, 1047, 1109, 1175,
1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865,
1976, 2093, 2217, 2349, 2489, 2637, 2794, 2960,
3136, 3322, 3520, 3729, 3951, 4186, 4435, 4699, 4978
]

def getPitch(noteNo):
global USE_TBL, NOTE_TBL
if USE_TBL:
return NOTE_TBL[noteNo]/2
else:
return freq_note_converter.from_note_index(noteNo).freq/2

ended = False

class Event():
Expand Down Expand Up @@ -46,9 +68,9 @@ def prev_note_off_event(chan):
if msg.type == "note_on" and msg.velocity > 0:
existing_evt = prev_note_off_event(msg.channel)
if existing_evt is not None:
existing_evt.arg = freq_note_converter.from_note_index(msg.note).freq/2
existing_evt.arg = getPitch(msg.note)
else:
evts.append(Event("FREQ_SET", msg.channel, freq_note_converter.from_note_index(msg.note).freq/2))
evts.append(Event("FREQ_SET", msg.channel, getPitch(msg.note)))
else:
# note off
evts.append(Event("FREQ_SET", msg.channel, 0))
Expand Down
7 changes: 4 additions & 3 deletions include/app/idle.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@
#include <sound/beeper.h>
#include <sound/sequencer.h>
#include <sensor/sensor.h>
#include <sound/yukkuri.h>

void app_idle_prepare(SensorPool*, Beeper*, NewSequencer*);
void app_idle_prepare(SensorPool*, Beeper*, NewSequencer*, Yukkuri*);
void app_idle_draw(FantaManipulator*);
void app_idle_process();

class AppShimIdle: public Renderable {
public:
AppShimIdle(SensorPool*sp, Beeper*b, NewSequencer*s) {
app_idle_prepare(sp, b, s);
AppShimIdle(SensorPool*sp, Beeper*b, NewSequencer*s, Yukkuri*y) {
app_idle_prepare(sp, b, s, y);
}

void render(FantaManipulator*fb) {
Expand Down
65 changes: 65 additions & 0 deletions include/app/playground.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#pragma once
#include <views/framework.h>
#include <device_config.h>

#if HAS(PLAYGROUND)

#include <fonts.h>
#include <state.h>

class AppShimPlayground: public Composite {
public:
AppShimPlayground() {
scroller = new StringScroll(&keyrus0808_font);
scroller->set_y_position(6);
scroller->render_mode = slides[slide].first;
scroller->set_string(slides[slide].second);
scroller->scroll_only_if_not_fit = false;
add_composable(scroller);
}

void render(FantaManipulator*fb) {
fb->clear();
int gridsize = 4;
bool gridcol = true;
for(int y = 0; y < fb->get_height(); y += gridsize) {
gridcol = ((y / 4) % 2) == 0;
for(int x = 0; x < fb->get_width(); x += gridsize) {
fb->rect(x, y, x + gridsize, y + gridsize, true, gridcol);
gridcol ^= 1;
}
}
Composite::render(fb);
}

void step() {
if(hid_test_key_state(KEY_LEFT) == KEYSTATE_HIT) {
pop_state(STATE_PLAYGROUND, TRANSITION_SLIDE_HORIZONTAL_RIGHT);
} else if(hid_test_key_any(KEY_RIGHT | KEY_UP | KEY_DOWN) == KEYSTATE_HIT) {
slide++;
if(slide >= slides.size()) slide = 0;
scroller->render_mode = slides[slide].first;
scroller->set_string(slides[slide].second);
}

Composite::step();
}

private:
StringScroll * scroller;
int slide = 0;
std::vector<std::pair<text_attributes_t, const char *>> slides = {
{TEXT_NORMAL, "Normal"},
{TEXT_NO_BACKGROUND, "No Bg"},
{TEXT_INVERTED, "Invert"},
{TEXT_OUTLINED, "Outline"},
{TEXT_OUTLINED | OUTLINE_INVERTED, "OutInv"},
{TEXT_NO_BACKGROUND | TEXT_INVERTED, "No Bg Inv"},
{TEXT_NO_BACKGROUND | TEXT_OUTLINED, "No Bg Outl"},
{TEXT_NO_BACKGROUND | TEXT_OUTLINED | OUTLINE_INVERTED, "No Bg InvOutl"},
{TEXT_NO_BACKGROUND | TEXT_INVERTED | TEXT_OUTLINED, "NoBg Inv Out"},
{TEXT_NO_BACKGROUND | TEXT_INVERTED | TEXT_OUTLINED | OUTLINE_INVERTED, "NoBg Inv InvOut"},
};
};

#endif
35 changes: 35 additions & 0 deletions include/app/weather.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#pragma once
#include <views/framework.h>
#include <views/weather/current_weather.h>
#include <views/weather/daily_forecast.h>
#include <views/weather/chart_precipitation.h>
#include <views/weather/chart_pressure.h>
#include <state.h>

class AppShimWeather: public ListView {
public:
AppShimWeather() {
conditions = new CurrentWeatherView();
forecast = new DailyForecastView(true);
precipitation = new WeatherPrecipitationChart(true);
pressure = new WeatherPressureChart(true);

add_view(conditions);
add_view(precipitation);
add_view(pressure);
add_view(forecast);
}

void step() override {
ListView::step();
if(hid_test_key_state(KEY_LEFT) == KEYSTATE_HIT) {
pop_state(STATE_WEATHER, TRANSITION_SLIDE_HORIZONTAL_RIGHT);
}
}

private:
WeatherPrecipitationChart * precipitation;
WeatherPressureChart * pressure;
CurrentWeatherView * conditions;
DailyForecastView * forecast;
};
12 changes: 12 additions & 0 deletions include/device_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

// ---- SOFTWARE FEATURE FLAGS

// Enable the playground app for shits and giggles
#define HAS_PLAYGROUND

// Enable the Wordnik API and Word Of The Day screen. UNSTABLE: Uses a lot of RAM for HTTPS.
#define HAS_WORDNIK_API

Expand All @@ -17,6 +20,9 @@
// Enable Wii Balance Board measuring. UNSTABLE: Uses Bluedroid (a FUCKTON of RAM), periodic disconnects or reboots without leaving a stack trace.
// #define HAS_BALANCE_BOARD_INTEGRATION

// Enable the yukkuri voice talking clock
#define HAS_AQUESTALK

// ---- HARDWARE

#ifdef ESP32
Expand Down Expand Up @@ -45,4 +51,10 @@
#endif
#endif

#if HAS(AQUESTALK)
#if !defined(LIBAQUESTALK_FOUND)
#error libaquestalk was not found. See `./lib/nonfree-aquestalk/README.md` on how to add it correctly, or disable `HAS_AQUESTALK` feature flag.
#endif
#endif

#endif
2 changes: 1 addition & 1 deletion include/devices/big_clock.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

// Plasma Information System OS (not DOS, there's no disk in it!)
#define PRODUCT_NAME "PIS-OS"
#define PRODUCT_VERSION "3.0"
#define PRODUCT_VERSION "3.5"

// ---- Connection to DISP BOARD ----
const gpio_num_t HWCONF_PLASMA_DATABUS_GPIOS[] = {
Expand Down
2 changes: 1 addition & 1 deletion include/devices/smol_clock.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

// Plasma Information System OS (not DOS, there's no disk in it!)
#define PRODUCT_NAME "microPIS-OS"
#define PRODUCT_VERSION "3.0"
#define PRODUCT_VERSION "3.5"

// ---- Connection to beeper ----
const gpio_num_t HWCONF_BEEPER_GPIO = GPIO_NUM_12;
Expand Down
8 changes: 4 additions & 4 deletions include/graphics/fanta_manipulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,19 @@ class FantaManipulator {
/// @param glyph Glyph code to place
/// @param x X position for the glyph
/// @param y Y position for the glyph
void put_glyph(const font_definition_t * font, const unsigned char glyph, int x, int y, bool invert = false);
void put_glyph(const font_definition_t * font, const unsigned char glyph, int x, int y, text_attributes_t style = TEXT_NORMAL);
/// @brief Draw a string with the specified font at the specified position in the Fanta buffer. Does not do any line wrapping.
void put_string(const font_definition_t *, const char *, int x, int y, bool invert = false);
void put_string(const font_definition_t *, const char *, int x, int y, text_attributes_t style = TEXT_NORMAL);
/// @brief Offset the contents of the buffer
/// @param dx Horizontal offset. Negative is to the left.
/// @param dy Vertical offset. Negative is to the top.
void scroll(int dx, int dy);
/// @brief Invert all pixels of the buffer
void invert();
/// @brief Draws a line using Bresenham's algorithm
void line(int x1, int y1, int x2, int y2);
void line(int x1, int y1, int x2, int y2, bool state = true);
/// @brief Draws a rectangle
void rect(int x1, int y1, int x2, int y2, bool fill);
void rect(int x1, int y1, int x2, int y2, bool fill, bool state = true);

/// @brief Get the width of the buffer in pixels
int get_width();
Expand Down
20 changes: 18 additions & 2 deletions include/graphics/font.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,23 @@ typedef struct font_definition {
const uint8_t* data;
} font_definition_t;

typedef uint8_t text_attributes_t;

typedef enum text_style : text_attributes_t {
/// @brief Normal text (black background, white text)
TEXT_NORMAL = 0,
/// @brief Render only text without background
TEXT_NO_BACKGROUND = 1 << 0,
/// @brief Render white text with a black outline.
TEXT_OUTLINED = 1 << 1,
/// @brief Invert the color of the text (white background, black text)
TEXT_INVERTED = 1 << 2,
/// @brief Invert the color of the outline (white instead of black)
OUTLINE_INVERTED = 1 << 3,
} text_style_t;

/// @brief Fetch a sprite from a font based on it's character code
extern sprite_t sprite_from_glyph(const font_definition_t*, char16_t glyph);
/// @param masked Whether the character should have no background (masked by itself)
extern sprite_t sprite_from_glyph(const font_definition_t*, char16_t glyph, bool masked);
/// @brief Measure a string's width when drawn with a specified font
extern unsigned int measure_string_width(const font_definition_t*, const char*);
extern unsigned int measure_string_width(const font_definition_t*, const char*, text_attributes_t attributes = TEXT_NORMAL);
3 changes: 2 additions & 1 deletion include/os_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@
// ----- WaveOut channels -----

#define pisosWAVE_CHANNEL_BEEPER 0
#define pisosWAVE_CHANNEL_SEQUENCER 1
#define pisosWAVE_CHANNEL_SEQUENCER 1
#define pisosWAVE_CHANNEL_YUKKURI 2
24 changes: 24 additions & 0 deletions include/service/owm/weather.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#pragma once
#include <freertos/FreeRTOS.h>
#include <service/time.h>

#define FORECAST_WEATHER_DAYS 4
#define FORECAST_WEATHER_HOURS 36

typedef enum weather_condition_code {
UNKNOWN = 0,
Expand Down Expand Up @@ -32,6 +36,23 @@ typedef struct current_weather {
char description[64];
} current_weather_t;

typedef struct forecast_weather {
float day_temperature_kelvin;
float night_temperature_kelvin;
int pressure_hpa;
weather_condition_t conditions;
unsigned int precipitation_percentage;
tk_date_t date;
} forecast_weather_t;

typedef struct hourly_weather {
float temperature_kelvin;
int pressure_hpa;
weather_condition_t conditions;
unsigned int precipitation_percentage;
tk_time_of_day_t time;
} hourly_weather_t;

typedef enum temperature_unit {
KELVIN,
CELSIUS,
Expand All @@ -48,4 +69,7 @@ bool weather_get_current(current_weather_t *);
/// @brief Set a dummy weather state for demo purposes
void weather_set_demo(current_weather_t *);

const forecast_weather_t * weather_get_forecast(int day_from_now);
const hourly_weather_t * weather_get_hourly(int hour_from_now);

float kelvin_to(float, temperature_unit_t);
11 changes: 2 additions & 9 deletions include/service/owm/weather_icons.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
#pragma once
#include <graphics/sprite.h>
#include <service/owm/weather.h>

extern const ani_sprite_t thunderstorm_icon;
extern const ani_sprite_t drizzle_icon;
extern const ani_sprite_t rain_icon;
extern const ani_sprite_t sun_icon;
extern const ani_sprite_t clouds_icon;
extern const ani_sprite_t broken_clouds_icon;
extern const ani_sprite_t overcast_icon;
extern const ani_sprite_t snow_icon;
extern const ani_sprite_t mist_icon;
const ani_sprite_t * sprite_from_conditions(weather_condition_t conditions);
Loading

0 comments on commit 7cfebae

Please sign in to comment.