Skip to content

Commit

Permalink
Merge pull request #2 from vladkorotnev/develop
Browse files Browse the repository at this point in the history
PIS-OS 1.2 / microPIS-OS 1.0
  • Loading branch information
vladkorotnev authored Jul 9, 2024
2 parents a752baf + 0c51bf1 commit 2f0d77e
Show file tree
Hide file tree
Showing 76 changed files with 1,736 additions and 206 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
captures/
.vscode/c_cpp_properties.json
.env
/src/weather_icons/src
51 changes: 47 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,52 @@
# Plasma Clock
# PIS-OS

Wall clock/weather info/etc, based around the weird plasma display I've picked up at an auction.
Personal Information System OS (formerly Plasma Information Screen OS).
(Not DOS, there is no disk in it! yet.)

**This project has high voltage, which could be lethal!!**
A somewhat portable relatively-stylish pixel-art clock/weather station.

## Display Info
## Predefined target devices

* `DEVICE_PLASMA_CLOCK`: a [clock](https://youtu.be/D4MiHmhhjeQ) that I built around a plasma screen from an old Japanese bus/train.
* `DEVICE_MICROPISOS`: a portable devkit for PIS-OS, using a 100x16 OLED from WinStar.

## Supported hardware and feature-flags

### Display (at least one required)

* Morio Denki 16101DS (see [below](#morio-denki-plasma-display-info), [driver](src/display//md_plasma.cpp), feature flag `HAS_OUTPUT_MD_PLASMA`)
* Winstar WEG010016A in 8-bit parallel mode ([driver](src/display/ws0010.cpp), feature flag `HAS_OUTPUT_WS0010`)

### Speaker (at least one required)

* Piezo speaker ([driver](src/sound/beeper.cpp), [music](src/sound/melodies.cpp))

### Haptics (WIP)

* Taptic Engine via 2N3904 transistor as an amp (WIP: wired in parallel with the speaker)

### Software flags

* `HAS_WORDNIK_API`: compile with the Word Of The Day service using [Wordnik API](https://developer.wordnik.com/). This requires SSL, so bloats the firmware size significantly.
* `HAS_BLUETOOTH_LE`: automatically set on ESP32. Required for Switchbot-over-BLE. Uses [NimBLE](https://github.com/apache/mynewt-nimble), but still increases firmware size significantly.
* `HAS_OTAFVU`: OTA updates via ArduinoOTA. Currently disabled due to partition size constraints from the above.

### Thermal sensors

* AM2322 over IIC ([driver](src/sensor/am2322.cpp), feature flag `HAS_TEMP_SENSOR`)
* Switchbot Meter over BLE (unstable, [driver](src/sensor/switchbot/api.cpp), feature flag `SWITCHBOT_METER_INTEGRATION`)

### Motion sensors

* Any which provides logic H when motion found, logic L when not found ([driver](src/sensor/motion.cpp), feature flag `HAS_MOTION_SENSOR`)

### Light sensors

* Opto-resistor in voltage divider mode ([driver](src/sensor/light.cpp), feature flag `HAS_LIGHT_SENSOR`)

## Morio Denki Plasma Display Info

**This display uses high voltage, which could be lethal!!**

The display comes from a bus or a train, supposedly.

Expand All @@ -20,5 +62,6 @@ More detailed info is available in the following articles:

* На русском: https://habr.com/ru/companies/timeweb/articles/808805/
* 日本語で: https://elchika.com/article/b9f39c29-64aa-42ab-8f73-e6e27a72bd0e/
* Demo video: https://youtu.be/D4MiHmhhjeQ

You can also read the quest I went through trying to get it to run "in real time" at [EEVBlog Forums](https://www.eevblog.com/forum/repair/trying-to-figure-out-if-a-vfd-displaydriver-is-broken-(74-series-logic)/).
13 changes: 13 additions & 0 deletions include/backup.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once
#include <stdint.h>
#include <strings.h>

typedef uint32_t partition_handle_t;

void unmount_partition(partition_handle_t);
bool mount_settings(const void** out_ptr, partition_handle_t* out_handle, size_t* out_size);
bool mount_crash(const void** out_ptr, partition_handle_t* out_handle, size_t* out_size);

bool begin_settings_write();
void write_settings_chunk(const char *, size_t);
void end_settings_write();
8 changes: 4 additions & 4 deletions include/console.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#pragma once
#include <plasma/font.h>
#include <plasma/framebuffer.h>
#include <graphics/font.h>
#include <graphics/framebuffer.h>
#include <freertos/FreeRTOS.h>
#include <freertos/queue.h>

/// @brief A simple low level console that does not utilize the Renderable tooling
class Console {
public:
Console(const font_definition_t*, PlasmaDisplayFramebuffer*);
Console(const font_definition_t*, DisplayFramebuffer*);
~Console();

void set_active(bool);
Expand All @@ -22,7 +22,7 @@ class Console {
void task();

private:
PlasmaDisplayFramebuffer * disp;
DisplayFramebuffer * disp;
const font_definition_t * font;
QueueHandle_t hQueue;
TaskHandle_t hTask;
Expand Down
32 changes: 32 additions & 0 deletions include/device_config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#ifndef FEATUREFLAG_H_
#define FEATUREFLAG_H_

#define HAS(x) defined(HAS_##x)

// ---- SOFTWARE FEATURE FLAGS
#define HAS_WORDNIK_API
// #define HAS_OTAFVU
//#define HAS_SWITCHBOT_METER_INTEGRATION // <- low on RAM with the board used in big-clock: wait until they disable HTTPS enforcement, or buy bigger ESP board

// ---- HARDWARE

#ifdef ESP32
#define HAS_BLUETOOTH_LE
#endif

#ifdef DEVICE_PLASMA_CLOCK
#include <devices/big_clock.h>
#endif

#ifdef DEVICE_MICROPISOS
#include <devices/smol_clock.h>
#endif

// ---- DEPENDENCY RULES
#if !HAS(BLUETOOTH_LE)
#if HAS(SWITCHBOT_METER_INTEGRATION)
#undef HAS_SWITCHBOT_METER_INTEGRATION
#endif
#endif

#endif
11 changes: 10 additions & 1 deletion include/hw_config.h → include/devices/big_clock.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,18 @@

#include <hal/gpio_hal.h>

#define HAS_OUTPUT_MD_PLASMA
#define HAS_VARYING_BRIGHTNESS
#define HAS_LIGHT_SENSOR
#define HAS_TEMP_SENSOR
#define HAS_MOTION_SENSOR

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

// ---- Connection to DISP BOARD ----

// Oh well, I hoped my ESP32 supports Dedicated GPIO but no!
const gpio_num_t HWCONF_PLASMA_DATABUS_GPIOS[] = {
GPIO_NUM_15,
GPIO_NUM_2,
Expand Down
32 changes: 32 additions & 0 deletions include/devices/smol_clock.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#pragma once

#include <hal/gpio_hal.h>

#define HAS_OUTPUT_WS0010
#define HAS_TEMP_SENSOR

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

// ---- Connection to beeper ----
const gpio_num_t HWCONF_BEEPER_GPIO = GPIO_NUM_12;
const uint8_t HWCONF_BEEPER_PWM_CHANNEL = 0;

// ---- Connection to temperature sensor ----
const gpio_num_t HWCONF_I2C_SDA_GPIO = GPIO_NUM_26;
const gpio_num_t HWCONF_I2C_SCL_GPIO = GPIO_NUM_25;

// ---- Connection to display ----
const gpio_num_t HWCONF_WS0010_DATABUS_GPIOS[] = {
GPIO_NUM_5,
GPIO_NUM_0,
GPIO_NUM_23,
GPIO_NUM_2,
GPIO_NUM_22,
GPIO_NUM_15,
GPIO_NUM_4,
GPIO_NUM_21
};
const gpio_num_t HWCONF_WS0010_RS_GPIO = GPIO_NUM_19;
const gpio_num_t HWCONF_WS0010_EN_GPIO = GPIO_NUM_18;
22 changes: 15 additions & 7 deletions include/plasma/iface.h → include/display/md_plasma.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
#pragma once
#include <device_config.h>

#if HAS(OUTPUT_MD_PLASMA)
#include <hal/gpio_hal.h>
#include <graphics/display_driver.h>

/// @brief Interface to the Morio Denki plasma display controller board
class PlasmaDisplayIface {
class MorioDenkiPlasmaDriver: public DisplayDriver {
public:
/// @brief Initialize the interface. Configures the GPIO and prepares the outputs for use, also disables the output and high voltage supply.
/// @param databus 8 pins connected to the display controller's pixel data bus, LSB to MSB
Expand All @@ -11,7 +15,7 @@ class PlasmaDisplayIface {
/// @param bright Pin connected to the display controller's BRIGHT pin
/// @param blanking Pin connected to the display controller's SHOW pin
/// @param hv_enable Pin connected to the high voltage supply's ENABLE pin
PlasmaDisplayIface(
MorioDenkiPlasmaDriver(
const gpio_num_t databus[8],
const gpio_num_t clock,
const gpio_num_t reset,
Expand All @@ -30,10 +34,8 @@ class PlasmaDisplayIface {
/// @brief Select between half or full brightness
void set_bright(bool bright);

/// @brief Send a half-column to the display controller
void write_stride(uint8_t stride);
/// @brief Send a full column to the display controller
void write_column(uint16_t column);
/// @brief Send an array of half-columns to the display controller
void write_fanta(const uint8_t * strides, size_t count);

private:
gpio_num_t databus_gpios[8];
Expand All @@ -45,4 +47,10 @@ class PlasmaDisplayIface {
void initialize();
inline void set_databus(uint8_t data);
inline void pulse_clock();
};
/// @brief Send a half-column to the display controller
void write_stride(uint8_t stride);
/// @brief Send a full column to the display controller
void write_column(uint16_t column);
};

#endif
51 changes: 51 additions & 0 deletions include/display/ws0010.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#pragma once
#include <graphics/display_driver.h>
#include <device_config.h>

#if HAS(OUTPUT_WS0010)
// Winstar WS0010 compatible OLED display
class Ws0010OledDriver: public DisplayDriver {
public:
/// @brief Initialize the interface. Configures the GPIO and prepares the outputs for use, also disables the output and high voltage supply.
/// @note Connect the RWB pin to be LOW as we won't be reading from the display.
/// @param databus 8 pins connected to the display controller's data bus, DB0 to DB7
/// @param rs Pin connected to the display controller's RS pin
/// @param en Pin connected to the display controller's E pin
Ws0010OledDriver(
const gpio_num_t databus[8],
const gpio_num_t rs,
const gpio_num_t en
);

/// @brief Reset the display controller
void reset();
void clear();

/// @brief Enable or disable the high voltage supply
void set_power(bool on);
/// @brief Show or hide the display contents, while keeping the scanning active
void set_show(bool show);

#if HAS(VARYING_BRIGHTNESS)
#warning WS0010 does not support brightness controls
void set_bright(bool bright) { }
#endif

/// @brief Send an array of half-columns to the display controller
void write_fanta(const uint8_t * strides, size_t count);

private:
gpio_num_t databus_gpios[8];
gpio_num_t rs_gpio;
gpio_num_t en_gpio;
bool is_writing_ddram;
uint8_t ddram_ptr;

void initialize();
inline void set_databus(uint8_t data);
inline void set_is_command(bool);
inline void pulse_clock();
void write_string(const char *);
void write_stride(uint8_t stride);
};
#endif
3 changes: 1 addition & 2 deletions include/fonts.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
#pragma once
#include <plasma/font.h>
#include <graphics/font.h>

extern const font_definition_t xnu_font;
extern const font_definition_t keyrus0808_font;
extern const font_definition_t keyrus0816_font;
extern const font_definition_t sg8bit_font;
extern const font_definition_t one_pixel_bar_font;
extern const font_definition_t fps_counter_font;
20 changes: 20 additions & 0 deletions include/graphics/display_driver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#pragma once
#include <device_config.h>

class DisplayDriver {
public:
/// @brief Reset the display controller
virtual void reset();
/// @brief Send an array of half-columns to the display controller
virtual void write_fanta(const uint8_t * strides, size_t count);

/// @brief Enable or disable the display power
virtual void set_power(bool on);
/// @brief Show or hide the display contents, while keeping the scanning active
virtual void set_show(bool show);

#if HAS(VARYING_BRIGHTNESS)
/// @brief Select between half or full brightness
virtual void set_bright(bool bright);
#endif
};
File renamed without changes.
File renamed without changes.
10 changes: 5 additions & 5 deletions include/plasma/framebuffer.h → include/graphics/framebuffer.h
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
#pragma once
#include "iface.h"
#include <graphics/display_driver.h>
#include "fanta_manipulator.h"
#include <freertos/FreeRTOS.h>
#include <freertos/semphr.h>
#include <freertos/event_groups.h>

/// @brief A framebuffer for driving the plasma display
class PlasmaDisplayFramebuffer {
class DisplayFramebuffer {
public:
static const int width = 101;
static const int height = 16;
/// @brief Size of the backing buffer in bytes
static const size_t PDFB_BUFFER_SIZE = width * (height / 8);

PlasmaDisplayFramebuffer(PlasmaDisplayIface * display);
~PlasmaDisplayFramebuffer();
DisplayFramebuffer(DisplayDriver * display);
~DisplayFramebuffer();

/// @brief Clears the display
void clear();
Expand All @@ -38,7 +38,7 @@ class PlasmaDisplayFramebuffer {
SemaphoreHandle_t buffer_semaphore;
EventGroupHandle_t vsync_group;
TaskHandle_t hTask;
PlasmaDisplayIface * display;
DisplayDriver * display;
FantaManipulator * shared_manipulator;
bool is_dirty;

Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion include/idle.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#pragma once
#include <plasma/framebuffer.h>
#include <graphics/framebuffer.h>
#include <sound/beeper.h>
#include <sensor/sensor.h>

Expand Down
3 changes: 3 additions & 0 deletions include/network/netmgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ class NetworkManager {
/// @brief Connect to a specified network. If connection succeeds, the network credentials are saved into NVRAM.
static void connect(const char * ssid, const char * pass);

/// @brief Get the active connection RSSI
static int rssi();

private:
static void wifi_event(WiFiEvent_t);
static void save_current_network();
Expand Down
Loading

0 comments on commit 2f0d77e

Please sign in to comment.