エンジニアの醤油漬け

醤油大好きなとあるエンジニアのブログ

Lily58 Proのディスプレイ表示(OLED)を改造してみる

f:id:ubansi:20190321201635j:plain
レイヤーと起動時間と入力回数を表示

前回 ubansi.hatenablog.com

前回は自作キーボードのハードウエア部分を作成した記事でしたが、

今回はLily58Proのソフトウエア部分の改造をしてみます。

(どちらかといえばこちらが本業)

環境構築

自作キーボードの多くはqmk_firmwareというC言語のファームウエアのフレームワークで動いています。

とりあえずGitHubで自分のリポジトリにfolkして 公式サイトの手順にそってビルド環境を構築しました。

OSはWin10ですがUnixシェル環境のmsys2を使ってビルドしています。

github.com

www.msys2.org

機能追加してみる

Lily58Proの場合はどうやら表示関連の機能が

qmk_firmware\keyboards\lily58\lib

の内部にまとめられているようなので、 こちらにソースを追加しました。

起動時間の表示機能の追加

起動時間のカウント処理をuptime_render.cとして追加しました。

#include <stdio.h>
#include "lily58.h"

char timelog_str[24] = {};

void set_timelog(void){
    uint32_t uptime_millsec = timer_read32();
    uint32_t uptime_sec = uptime_millsec / 1000;
    int seconds = (int)(uptime_sec % 60);
    int minutes = (int)(uptime_sec / 60  % 60);
    int hour = (int)(uptime_sec / 60 / 60);
    snprintf(timelog_str, sizeof(timelog_str), "uptime: %02d:%02d:%02d", hour, minutes, seconds);
}

const char *read_timelog(void) {
  return timelog_str;
}

起動時間に関してはデフォルトで計測されているので、 ただ関数を呼び出すだけで起動時間がミリ秒で取得できます。 ただし、timer_read()で呼び出した場合には戻り型がint型になっていまい すぐにオーバーフローしてしまいます。 なので、32ビット型のtimer_read32()で値を取得しています。

取得したミリ秒はよくやるパターンで60進数に変換してます。 snprintfで表示用の文字列を作成して指定した配列に代入しています。

最近は高級言語ばかりいじっていたので オーバーフローなんて久々にしました。

あとは他のrender関数にならって、 char配列に生成した文字列を格納して保持し、 getter的な役割をするread_timelog関数を用意しました。

(2019-03-31追記:キャストタイミングのミスで、長時間接続時に秒、分がオーバーフローするバグの修正)

タイプ数をカウントする機能の追加

タイプ数のカウント処理も同様にtypecount_render.cとして作成しました。

#include <stdio.h>
#include "lily58.h"

uint32_t type_count = 0;
char countlog_str[24] = {};

 void count_up(void){
    type_count++;
    snprintf(countlog_str, sizeof(countlog_str),"Type Count: %"PRId32"",type_count);
}

 const char *read_countlog(void) {
  return countlog_str;
} 

こっちはただカウントして文字列生成するだけです。

(2019-03-24追記:結構すぐint上限の3万を越えてしまうのでint->uint32_tに型変更しました。)

keymap.c,rules.mk

OLEDのディスプレイ表示関連をやっているのはkeymap.cmatrix_render_user関数です。 どうやらユーザーが自由にカスタムするための関数っぽいですね。

void matrix_render_user(struct CharacterMatrix *matrix) {
  set_timelog();

  if (is_master) {
    // If you want to change the display of OLED, you need to change here
    matrix_write_ln(matrix, read_layer_state());
    //matrix_write_ln(matrix, read_keylog());
    //matrix_write_ln(matrix, read_keylogs());
    //matrix_write_ln(matrix, read_mode_icon(keymap_config.swap_lalt_lgui));
    //matrix_write_ln(matrix, read_host_led_state());
    //matrix_write_ln(matrix, read_timelog());
    matrix_write_ln(matrix, read_timelog());
    matrix_write_ln(matrix, read_countlog());

  } else {
    matrix_write(matrix, read_logo());
  }
}

こんな感じでread_timelog, read_countlogを呼び出し表示処理につなげます。

(2019-03-24追記:set_timelog();matrix_render_userに移動することでリアルタイムに更新されるようになりました。教えてくれた@sirojake さんに感謝)

あとはキーイベントをキャッチして呼び出すために、 provess_record_user内部にカウント処理を追加します

bool process_record_user(uint16_t keycode, keyrecord_t *record) {
  if (record->event.pressed) {
#ifdef SSD1306OLED
    set_keylog(keycode, record);
    count_up();
#endif
  }

...

あと、ファイルの外部の関数を呼び出せるように上の方で、

void count_up(void);
const char *read_countlog(void);
void set_timelog(void);
const char *read_timelog(void);

を追加しましょう。

次はビルド時にソースが読み込まれるようにrules.mkを変更します。 ただ、自分の場合これだけだと容量オーバーでだめでした。

自分の場合はRGBライトは使っていないので、関連コードをビルド時に除外するように無効化しました。

# If you want to change the display of OLED, you need to change here
SRC +=  ./lib/glcdfont.c \
        ./lib/layer_state_reader.c \
        ./lib/logo_reader.c \
        ./lib/uptime_render.c \
        ./lib/typecount_render.c \
        ./lib/keylogger.c \
        # ./lib/mode_icon_reader.c \
        # ./lib/host_led_state_reader.c \
        # ./lib/timelogger.c \
        # ./lib/rgb_state_reader.c \
        

上の方でもnoに設定するのを忘れずに

RGBLIGHT_ENABLE = no       # Enable WS2812 RGB underlight. 

これでビルドすれば起動時間とタイプ数の表示機能が追加されます。

実際の動き

入力するたびにカウンタが増えていくのがわかるはず。

ソースコードについて

今回書き換えた内容は以下のプルリクエストで見られます。

github.com

ロゴアイコンを変更してみる

f:id:ubansi:20190321201311j:plain
ケムリクサEDからりんのシルエットを拝借
この記事を参考にして変更しました。

qiita.com

ケムリクサ11話視聴後なので、書き換えるしかなかったです。

ロゴアイコン書き換えをやってみて思ったのは、

  • 32x128は小さい
  • モノクロだと表現が難しい

でした。 シルエットなどはいけますが、 キャラなどは難しいですね。

これはモノクロドット絵を勉強するか、ディスプレイ交換することになるかもです。

あとがき

これで前回の記事で書いた目標の OLEDの内容書き換えたい を達成しました。

ちなみにLEDのスイッチングに関してはまだ調査中で どうもPWM制御に対応しているピンが全て使われているようで難しそうだなと思っています。

アンダーグローライト制御用ピンとPWM対応ピンをファームウエアで入れ替えて、 配線も入れ替えれば行けるかも?とか思ってますが非常に面倒そう。

まぁ光っててもかっこいいだけなので 優先度下げて対応かなと思います。

キーの作成はレジンで作成しようかと考えてます。 そちらもそのうち取り組めると良いかなともいます。

※ちなみにこの記事は、Lily58Proを使って執筆しました。