Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
akasaka committed Nov 25, 2024
2 parents 7e4b172 + a040d2a commit ad4568e
Show file tree
Hide file tree
Showing 18 changed files with 9,118 additions and 0 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ More photos in [the gallery](https://pis-os.genjit.su/index.html#photos)
* [Owl City - Fireflies](https://www.youtube.com/watch?v=psuRGfAaju4): [MIDI](helper/chimes/fireflies.mid)
* [Ado - Odo](https://www.youtube.com/watch?v=YnSW8ian29w): [MIDI](helper/chimes/odo.mid)
* [ZUN - Legend of Hourai](https://www.youtube.com/watch?v=d2_tY7cl818): [MIDI](helper/chimes/hourai_sou1.mid) based on work by sou1
* [Hiiragi Magnetite — Antenna 39](https://www.youtube.com/watch?v=7yJRsFFRoQY): [Recording](https://www.youtube.com/watch?v=zYAEvVJUqVs), [MIDI](helper/chimes/antenna39.mid)
* [daniwellP - Nyan Cat](https://www.youtube.com/watch?v=LfKCLdPTqtM): [MIDI](helper/chimes/nyancat.mid), [MP3](docs/rec/squarecat.mp3)
* [Neru - Tokyo Teddy Bear](https://www.youtube.com/watch?v=eSI7RsjZy1E): [MIDI](helper/chimes/tokyoteddybear.mid) based on [MIDI by FDG/Danny G](https://www.youtube.com/watch?v=Y30ZyZbRCrE)
* [LamazeP - Triple Baka](https://open.spotify.com/track/2dE6zWGJXZuqvfengytVGo): [MIDI](helper/chimes/3baka.mid) based on [MIDI by FDG/Danny G](https://www.youtube.com/watch?v=HNPrwdLJC8g), [MP3](docs/rec/baka.mp3)

## Creating your own melodies

Expand Down
Binary file added data/music/039_nyancat.pomf
Binary file not shown.
Binary file added data/music/040_tokyo_teddy_bear.pomf
Binary file not shown.
Binary file added data/music/041_triple_baka.pomf
Binary file not shown.
Binary file added docs/rec/baka.mp3
Binary file not shown.
Binary file added docs/rec/squarecat.mp3
Binary file not shown.
Binary file added helper/chimes/3baka.mid
Binary file not shown.
Binary file added helper/chimes/nyancat.mid
Binary file not shown.
Binary file added helper/chimes/tokyoteddybear.mid
Binary file not shown.
4 changes: 4 additions & 0 deletions include/device_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@
#include <devices/led_clock.h>
#endif

#ifdef DEVICE_LONGPISOS
#include <devices/big_noritake.h>
#endif

// ---- DEPENDENCY RULES
#if !HAS(BLUETOOTH_LE)
#if HAS(SWITCHBOT_METER_INTEGRATION)
Expand Down
41 changes: 41 additions & 0 deletions include/devices/big_noritake.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#pragma once

#include <hal/gpio_hal.h>
#include <input/keypad.h>

#define HAS_OUTPUT_GU312
#define HAS_KEYPAD

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

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

// ---- Connection to display ----
const gpio_num_t HWCONF_GU312_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_GU312_CD_GPIO = GPIO_NUM_19;
const gpio_num_t HWCONF_GU312_WR_GPIO = GPIO_NUM_18;

#define HWCONF_DISPLAY_WIDTH_PX 192
#define HWCONF_DISPLAY_HEIGHT_PX 16

// ---- Connection of buttons ----
const keypad_definition_t HWCONF_KEYPAD = {
{GPIO_NUM_14, KEY_RIGHT},
{GPIO_NUM_32, KEY_LEFT},
{GPIO_NUM_34, KEY_UP},
{GPIO_NUM_27, KEY_DOWN},
{GPIO_NUM_35, KEY_HEADPAT},
};
7 changes: 7 additions & 0 deletions include/display/display.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ static AkizukiK875Driver display_driver(
HWCONF_K875_SIN3_GPIO,
HWCONF_K875_SACRIFICIAL_GPIO
);
#elif HAS(OUTPUT_GU312)
#include <display/gu312.h>
static NoritakeGu312Driver display_driver(
HWCONF_GU312_DATABUS_GPIOS,
HWCONF_GU312_CD_GPIO,
HWCONF_GU312_WR_GPIO
);
#else
#error Display module type not selected
#endif
49 changes: 49 additions & 0 deletions include/display/gu312.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#pragma once
#include <graphics/display_driver.h>
#include <device_config.h>

#if HAS(OUTPUT_GU312)
class NoritakeGu312Driver: 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 CS to LOW
/// @param databus 8 pins connected to the display controller's data bus, DB0 to DB7
/// @param cd Pin connected to the display controller's C/D pin
/// @param wr Pin connected to the display controller's WR pin
/// @param blank Pin connected to the display controller's blanking pin
NoritakeGu312Driver(
const gpio_num_t databus[8],
const gpio_num_t cd,
const gpio_num_t wr
// const gpio_num_t blank
);

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

/// @brief Enable or disable the high voltage supply
void set_power(bool on);

/// @brief Enable or disable dimming
void set_bright(bool bright);

/// @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 cd_gpio;
gpio_num_t wr_gpio;

void send_command(uint8_t cmd);
inline void set_databus(uint8_t data);
inline void set_is_command(bool);
inline void pulse_clock();
void write_string(const char *);

bool power_state;
void _set_pmu_internal();
};
#endif
8 changes: 8 additions & 0 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ upload_speed = 921600
monitor_speed = 115200
monitor_filters = esp32_exception_decoder

[env:NORITAKE_321_192]
board = esp32dev
build_type = debug
build_flags = -DDEVICE_LONGPISOS -DFVU_FLAVOR=\"NORITAKE_321_192\" ${common.build_flags} -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue -DCONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
upload_speed = 921600
monitor_speed = 115200
monitor_filters = esp32_exception_decoder

[env:AKI_K875]
board = esp32dev
build_type = debug
Expand Down
206 changes: 206 additions & 0 deletions src/display/gu312.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
#include <device_config.h>

// This is a result of reverse engineering a bus display that uses a half meter long GU192x16-321.
// Mostly similar to the old noritake protocol but there are some undocumented states.
// The pinout is also undocumented so here goes
// 1 2
// +______+
// D7>| . . | GND
// D6 | . . | GND
// D5 | . . | GND
// D4 | . . | GND
// D3 | . . | GND
// D2 | . . | GND
// D1 | . . | GND
// D0 | . . | GND
// ~WR | . . GND
// A0 | . . | GND
// ~RD | . . | GND
// A1 | . . | ???
// FEP | . . | ~BL <-- note: FEP is Vsync out FROM the display!. ~BL=0 turns display off.
// GND | . . | GND
//~RST | . . | GND
// A2 | . . | GND
// ~CS | . . | GND
// +------+
// 33 34





#if HAS(OUTPUT_GU312)
#include "display/gu312.h"
#include <esp32-hal-log.h>
#include <esp32-hal-gpio.h>
#include <esp_err.h>

static char LOG_TAG[] = "Gu312";
static portMUX_TYPE _spinlock = portMUX_INITIALIZER_UNLOCKED;

NoritakeGu312Driver::NoritakeGu312Driver(
const gpio_num_t databus[8],
const gpio_num_t cd,
const gpio_num_t wr
) {
for(int i = 0; i < 8; i++) {
databus_gpios[i] = databus[i];
}
cd_gpio = cd;
wr_gpio = wr;
power_state = false;
}

void NoritakeGu312Driver::initialize() {
ESP_LOGI(LOG_TAG, "Initializing Noritake Itron GU312 with data bus: %i %i %i %i %i %i %i %i, cd=%i, wr=%i", databus_gpios[0], databus_gpios[1], databus_gpios[2], databus_gpios[3], databus_gpios[4], databus_gpios[5], databus_gpios[6], databus_gpios[7], cd_gpio, wr_gpio);

gpio_config_t io_conf = {
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = gpio_pullup_t::GPIO_PULLUP_ENABLE,
};

for(int i = 0; i < sizeof(databus_gpios) / sizeof(databus_gpios[0]); i++) {
io_conf.pin_bit_mask |= 1ULL << databus_gpios[i];
}

io_conf.pin_bit_mask |= 1ULL << cd_gpio;
io_conf.pin_bit_mask |= 1ULL << wr_gpio;

ESP_ERROR_CHECK(gpio_config(&io_conf));

gpio_set_level(wr_gpio, 1);
gpio_set_level(cd_gpio, 0);

delay(500);
}

void NoritakeGu312Driver::set_databus(uint8_t data) {
uint8_t local_sts = data;
for(int i = 0; i < 8; i++) {
uint8_t cur_state = (local_sts & 1);
gpio_set_level(databus_gpios[i], cur_state);
local_sts >>= 1;
}
}

void NoritakeGu312Driver::pulse_clock() {
gpio_set_level(wr_gpio, 0);
delayMicroseconds(2);
gpio_set_level(wr_gpio, 1);
delayMicroseconds(2);
}

void NoritakeGu312Driver::set_is_command(bool rs) {
// H: COMMAND, L: Data
gpio_set_level(cd_gpio, rs ? 1 : 0);
delayMicroseconds(3);
}

void NoritakeGu312Driver::write_string(const char * s) {
set_is_command(false);
int len = strlen(s);
for(int i = 0; i < len; i++) {
set_databus(s[i]);
pulse_clock();
delayMicroseconds(100);
}
}

void NoritakeGu312Driver::send_command(uint8_t cmd) {
set_is_command(true);
set_databus(cmd);
pulse_clock();
set_is_command(false);
}

void NoritakeGu312Driver::reset() {
ESP_LOGI(LOG_TAG, "Resetting");
taskENTER_CRITICAL(&_spinlock);

send_command(0b11000); // brightness max
send_command(0b00010); // SCR2 on
send_command(0b00111); // SCR2 graphic
send_command(0b00100); // cursor auto increment

send_command(0b01010); // set read pos SCR#1 Low
set_databus(0x80); pulse_clock();
send_command(0b01011); // set read pos SCR#1 High
set_databus(0x1); pulse_clock();

send_command(0b01100); // set read pos SCR#2 Low
set_databus(0x0); pulse_clock();
send_command(0b01101); // set read pos SCR#2 High
set_databus(0xc); pulse_clock();

// put all 0 in SCR1
send_command(0b01110); // set write pos Low
set_databus(0x0); pulse_clock();
send_command(0b01111); // set write pos High
set_databus(0xc); pulse_clock();
send_command(0b01000); // WRITE mode

for(int i = 0; i < 192 * 8; i++) {
set_databus(0xAA);
pulse_clock();
}

ESP_LOGI(LOG_TAG, "Reset complete");

taskEXIT_CRITICAL(&_spinlock);
// while(true) vTaskDelay(portMAX_DELAY);
}

void NoritakeGu312Driver::set_power(bool power) {
power_state = power;
_set_pmu_internal();
}

void NoritakeGu312Driver::clear() {
taskENTER_CRITICAL(&_spinlock);

taskEXIT_CRITICAL(&_spinlock);
}

inline uint8_t flipByte(uint8_t c){
char r=0;
for(uint8_t i = 0; i < 8; i++){
r <<= 1;
r |= c & 1;
c >>= 1;
}
return r;
}

void NoritakeGu312Driver::write_fanta(const uint8_t * strides, size_t count) {
taskENTER_CRITICAL(&_spinlock);
send_command(0b01110); // set write pos Low
set_databus(0); pulse_clock();
send_command(0b01111); // set write pos High
set_databus(0xc); pulse_clock();
send_command(0b01000); // WRITE mode
for(int i = 0; i < count; i++) {
set_databus(flipByte(strides[i]));
pulse_clock();
if(i % 2 != 0) {
set_databus(0);
for(int i = 0; i < 6; i++) pulse_clock();
}
}
send_command(0b00010);
taskEXIT_CRITICAL(&_spinlock);
}

void NoritakeGu312Driver::set_bright(bool bright) {
taskENTER_CRITICAL(&_spinlock);
send_command(bright ? 0b11001 : 0b11011);
// undocumented: can go from 11000 (100%) to as low as 11111 (undocumented)
taskEXIT_CRITICAL(&_spinlock);
}

void NoritakeGu312Driver::_set_pmu_internal() {
taskENTER_CRITICAL(&_spinlock);

taskEXIT_CRITICAL(&_spinlock);
}

#endif
Loading

0 comments on commit ad4568e

Please sign in to comment.