昨日営業再開しました。
ぼっちはコロナにも負けない。
入店前に手をアルコール消毒し、お肉を取りに行く時は、お店で用意されたビニール手袋とマスクをつけてください、ということでした。
久しぶりのお店焼肉・・・
堪能して参りました。

花火、きれいでしたねー
さて、いよいよRASの実装が近づいてきましたよ~

ノスタルジックレインフォール
テレビアニメ「恋は雨上がりのように」のOPテーマです。
予想レベル24


ほぼほぼバンドリ3rdシーズンの内容ですね。

EXPOSE ‘Burn Out!!!’がイベント開始と同時に実装されます。
予想レベル26

同時にカバー曲「ヒトリノ夜」が実装されます。
アニメ「GTO」のOPテーマでした。
カバーコレクションに収録されている曲ですね。
予想レベル25

イベント後編にはバンドリ3rdシーズンの13話で披露されたBeautiful Birthdayが実装されます。

まとめ。


イベントは6月10日開始です。
次のイベントですね。


星配布と無料ガチャは嬉しい。
イベントで勝ち抜くにはメンツが必要。
ガチ課金勢には敵わないけどな。

前回までの状況はこちら。
PythonコードをgitHubにアップしました。
https://github.com/takishita2nd/GLCD
サンプルソースにフォントのビットパターンデータがありましたので、これを置換処理を使ってPython用に書き換えました。
https://github.com/takishita2nd/GLCD/blob/master/Font.py
これを使用して、ディスプレイにアスキー文字を表示させます。
[ 0x7e, 0x11, 0x11, 0x11, 0x7e ], # A 0x41
1文字8×5のサイズになっているようです。
お試しで表示させてみました。
chara = [0x7e, 0x11, 0x11, 0x11, 0x7e]
def __main():
PinsInit(20, 7, 8, 9, 18, 19, 10, 11, 12, 13, 14, 15, 16, 17)
GLCDInit()
GLCDDisplayClear()
addr = 0
SelectIC(1)
SetPage(0)
for c in chara:
SetAddress(addr)
WriteData(c)
addr += 1
try:
while True:
time.sleep(1.0)
except KeyboardInterrupt:
GPIO.cleanup()

このデータを表示するサンプルコードをPython用に書き換えました。
def GLCDPutc(Xp, Yp, c):
code = ord(c)
#ページ内のラインを選択
L = Yp % 8
#8×5のキャラクター文字を描画する
for i in range(5):
SetLocation(Xp + i, Yp)
f = Font.Array[code - 0x20][i] << L
WriteData(f)
if (L != 0) & (SetPg < 7):
SetPage(SetPg + 1)
SetAddress(SetCol)
f = Font.Array[code - 0x20][i] >> (8 - L)
WriteData(f)
def SetLocation(Xp, Yp):
global SetPg
global SetCol
cs = 0
#チップの選択とカラムのアドレスの処理を行う
if Xp < 64:
#左側(IC1)を選択
cs = 1
SetCol = Xp
else:
#右側(IC2)を選択
cs = 2
SetCol = Xp - 64
#ページとラインの選択
SetPg = Yp // 8
#LCDに描画するアドレスの位置を設定
SelectIC(cs)
SetPage(SetPg)
SetAddress(SetCol)
好きな場所に文字を書くことができます。
ページ跨ぎとか、チップ跨ぎにも対応しているようです。
def __main():
PinsInit(20, 7, 8, 9, 18, 19, 10, 11, 12, 13, 14, 15, 16, 17)
GLCDInit()
GLCDDisplayClear()
GLCDPutc(20, 5, "B")
try:
while True:
time.sleep(1.0)
except KeyboardInterrupt:
GPIO.cleanup()


前回までの状況はこちら。
最新ソースはこちら(gitHub)
https://github.com/takishita2nd/diet-mng
データ削除処理を作成します。
とはいっても、もう追加、編集処理が出来上がっているので、そんなに難しくありませんでした。
ぱぱっとやってしまいます。
public function delete($id, $user)
{
$model = $this->getItemById($id);
$this->detachToUser($model, $user);
$model->delete();
}
/**
* データを1件削除する
*/
public function delete(Request $request)
{
$this->weightManagement->delete($request->contents["id"], Auth::user());
return response()->json();
}
Route::post('api/weight/delete', 'Weight\ApiController@delete');
<template>
<div>
<div id="overlay" v-show="show">
<div id="content">
<p v-if="error_flg == true" class="error">
<ui>
<li v-for="error in errors">{{ error }}</li>
</ui>
</p>
<table class="edit">
<tbody>
<tr>
<td>日時</td>
<td>{{contents.date}}</td>
</tr>
<tr>
<td>体重</td>
<td>{{contents.weight}}</td>
</tr>
<tr>
<td>体脂肪</td>
<td>{{contents.fat_rate}}</td>
</tr>
<tr>
<td>BMI</td>
<td>{{contents.bmi}}</td>
</tr>
</tbody>
</table>
<p id="command">
<button @click="clickDelete">OK</button>
<button @click="closeModal">キャンセル</button>
</p>
</div>
</div>
</div>
</template>
<script>
export default {
props: ['show'],
data() {
return {
errors: [],
error_flg: [],
param: {},
contents: {
date: "",
weight: "",
fat_rate: "",
bmi: "",
},
};
},
created: function() {
},
methods: {
dataSet: function(data) {
this.contents = data;
},
clickDelete: function() {
var self = this;
this.param.contents = this.contents;
axios.post('api/weight/delete', this.param).then(function(response){
self.closeModal();
self.$emit('update');
}).catch(function(error){
self.error_flg = true;
self.errors = error.response.data.errors;
});
},
closeModal: function() {
this.$parent.showDeleteDialogContent = false;
},
}
}
</script>
<weight-delete-dialog-component ref="deleteDialog" :show="showDeleteDialogContent" @update="invokeUpdateList"></weight-delete-dialog-component>
onClickDelete: function(id) {
var editData = {};
this.datalists.forEach(element => {
if(element.id == id){
editData.id = id;
editData.date = element.date;
editData.weight = element.weight;
editData.fat_rate = element.fat_rate;
editData.bmi = element.bmi;
return true;
}
});
this.$refs.deleteDialog.dataSet(editData);
this.showDeleteDialogContent = true;
},
いいかんじです。
前回までの状況はこちら。
最新ソースはこちら。(gitHub)
https://github.com/takishita2nd/Picross
いままではデータ入力値がパレットの陰に隠れて見えづらい、という問題をうすうすと感じていましたが、これを修正したいと思います。
具体的には、パレットの上に入力値を表示し、ENTERボタンを押下することで入力データを反映させます。
なので、パレットを拡張。

そして、パレット周りの処理をがっつり書き換えました。
class Palette
{
public void OnClick(asd.Vector2DF pos)
{
if (paletteZeroSquareObject.IsClick(pos))
{
if(_valueText.Text != "" && _valueText.Text != "0")
{
if (_valueText.Text.Length < 2)
{
_valueText.Text += "0";
}
}
}
else if (paletteBSSquareObject.IsClick(pos))
{
if(_valueText.Text.Length > 0)
{
_valueText.Text = _valueText.Text.Remove(_valueText.Text.Length - 1);
}
}
else if (paletteCRSquareObject.IsClick(pos))
{
_valueText.Text = "";
}
else if (paletteENSquareObject.IsClick(pos))
{
value = _valueText.Text;
_isClickEnter = true;
}
else
{
for (int row = 0; row < 3; row++)
{
for (int col = 0; col < 3; col++)
{
if (paletteSquareObjects[row, col].IsClick(pos) == true)
{
if(_valueText.Text.Length < 2)
{
if(_valueText.Text == "0")
{
_valueText.Text = paletteSquareObjects[row, col].GetValue();
}
else
{
_valueText.Text += paletteSquareObjects[row, col].GetValue();
}
}
}
}
}
}
}
public bool IsClickEnter()
{
return _isClickEnter;
}
public string GetValue()
{
return value;
}
パレットを使用する側もがっつり書き換えます。
if (palette.IsClick(pos))
{
string value = string.Empty;
palette.OnClick(pos);
if(palette.IsClickEnter())
{
palette.Hide();
if (selectedNumberSquare != null)
{
selectedNumberSquare.SetValue(palette.GetValue());
if (selectedNumberSquare.GetStringValue() != string.Empty)
{
if (selectedRowIndex >= 0)
{
if (Math.Abs(selectedColIndex - 1) > rowNumberSquare[selectedRowIndex].Count)
{
var square = new NumberSquare(selectedRowIndex, selectedColIndex - 1);
asd.Engine.AddObject2D(square.getBackTexture());
asd.Engine.AddObject2D(square.getTextObject());
rowNumberSquare[selectedRowIndex].Add(square);
}
}
else if (selectedColIndex >= 0)
{
if (Math.Abs(selectedRowIndex - 1) > colNumberSquare[selectedColIndex].Count)
{
var square = new NumberSquare(selectedRowIndex - 1, selectedColIndex);
asd.Engine.AddObject2D(square.getBackTexture());
asd.Engine.AddObject2D(square.getTextObject());
colNumberSquare[selectedColIndex].Add(square);
}
}
}
else
{
if (selectedRowIndex >= 0)
{
if (Math.Abs(selectedColIndex - 1) <= rowNumberSquare[selectedRowIndex].Count)
{
asd.Engine.RemoveObject2D(rowNumberSquare[selectedRowIndex][Math.Abs(selectedColIndex + 1)].getBackTexture());
asd.Engine.RemoveObject2D(rowNumberSquare[selectedRowIndex][Math.Abs(selectedColIndex + 1)].getTextObject());
rowNumberSquare[selectedRowIndex].RemoveAt(Math.Abs(selectedColIndex + 1));
for (int col = selectedColIndex + 1; Math.Abs(col) < rowNumberSquare[selectedRowIndex].Count; col--)
{
rowNumberSquare[selectedRowIndex][Math.Abs(col)].SetPosition(selectedRowIndex, col - 1);
}
}
}
else if (selectedColIndex >= 0)
{
if (Math.Abs(selectedRowIndex - 1) <= colNumberSquare[selectedColIndex].Count)
{
asd.Engine.RemoveObject2D(colNumberSquare[selectedColIndex][Math.Abs(selectedRowIndex + 1)].getBackTexture());
asd.Engine.RemoveObject2D(colNumberSquare[selectedColIndex][Math.Abs(selectedRowIndex + 1)].getTextObject());
colNumberSquare[selectedColIndex].RemoveAt(Math.Abs(selectedRowIndex + 1));
for (int row = selectedRowIndex + 1; Math.Abs(row) < colNumberSquare[selectedColIndex].Count; row--)
{
colNumberSquare[selectedColIndex][Math.Abs(row)].SetPosition(row - 1, selectedColIndex);
}
}
}
selectedNumberSquare.SetValue("0");
}
selectedNumberSquare = null;
}
}
}
else
{
palette.Hide();
}
とりあえず、UI周りはこれで十分かと思います。
じゃあ、ロジックに戻りましょうか。

前回までの状況はこちら。
最新ソースはこちら(gitHub)
https://github.com/takishita2nd/diet-mng
データ編集・更新できるようにします。
まず、編集ダイアログのコンポーネントですが、入力のときと別物にしましょう。
同じコンポーネントも使えるかもしれないけど、いろいろめんどくさい。
<template>
<div>
<div id="overlay" v-show="show">
<div id="content">
<p v-if="error_flg == true" class="error">
<ui>
<li v-for="error in errors">{{ error }}</li>
</ui>
</p>
<table class="edit">
<tbody>
<tr>
<td>体重</td>
<td><input type="number" v-model="contents.weight" /></td>
</tr>
<tr>
<td>体脂肪</td>
<td><input type="number" v-model="contents.fat_rate" /></td>
</tr>
<tr>
<td>BMI</td>
<td><input type="number" v-model="contents.bmi" /></td>
</tr>
</tbody>
</table>
<p id="command">
<button @click="clickAdd">入力</button>
<button @click="closeModal">閉じる</button>
</p>
</div>
</div>
</div>
</template>
<script>
export default {
props: ['show'],
data() {
return {
errors: [],
error_flg: [],
param: {},
contents: {
id: "",
weight: "",
fat_rate: "",
bmi: "",
},
};
},
created: function() {
},
methods: {
dataSet: function(data) {
this.contents = data;
},
clickAdd: function() {
var self = this;
this.param.contents = this.contents;
axios.post('api/weight/edit', this.param).then(function(response){
self.clear();
self.closeModal();
self.$emit('update');
}).catch(function(error){
self.error_flg = true;
self.errors = error.response.data.errors;
});
},
closeModal: function() {
this.$parent.showEditDialogContent = false;
},
clear: function() {
this.contents.weight = "";
this.contents.fat_rate = "";
this.contents.bmi = "";
this.error_flg = false;
this.errors = [];
}
}
}
</script>
そして、それを使用する側の親コンポーネント。
<div>
<weight-input-dialog-component :show="showInputDialogContent" @update="invokeUpdateList"></weight-input-dialog-component>
<weight-edit-dialog-component ref="editDialog" :show="showEditDialogContent" @update="invokeUpdateList"></weight-edit-dialog-component>
</div>
onClickEdit: function(id) {
var editData = {};
this.datalists.forEach(element => {
if(element.id == id){
editData.id = id;
editData.weight = element.weight;
editData.fat_rate = element.fat_rate;
editData.bmi = element.bmi;
return true;
}
});
this.$refs.editDialog.dataSet(editData);
this.showEditDialogContent = true;
ポイントは、編集ダイアログにデータを渡すとき。
親コンポーネントから子コンポーネントのメソッドをコールしています。
これは、子コンポーネントを定義するときに、
ref="editDialog"
と書くことで、
this.$refs.editDialog.dataSet(editData);
と、子コンポーネントのメソッドを実行できます。
その引数でパラメータを渡して、表示させています。
あとは、今までどおり。
Repository
public function edit($id, $weight, $fat_rate, $bmi)
{
$model = $this->getItemById($id);
$model->weight = $weight;
$model->fat_rate = $fat_rate;
$model->bmi = $bmi;
$model->save();
}
public function getItemById($id)
{
return WeightManagement::where(['id' => $id])->first();
}
controller
/**
* データを1件更新する
*/
public function edit(Request $request)
{
$param = $this->weightManagement->getParam();
$this->weightManagement->edit( $request->contents["id"],
$request->contents["weight"],
$request->contents["fat_rate"],
$request->contents["bmi"]
);
return response()->json();
}
Route::post('api/weight/edit', 'Weight\ApiController@edit');

前回までの状況はこちら。
前回でLCDディスプレイの初期化も終わってますし、データを書き込む関数も一通り揃っています。
なので、いろいろ書いてみましょうか。
とはいっても、今の状態では、ドット単位で表示する/しないの設定しかできませんが。
def __main():
PinsInit(20, 7, 8, 9, 18, 19, 10, 11, 12, 13, 14, 15, 16, 17)
GLCDInit()
GLCDDisplayClear()
SelectIC(1)
SetPage(0)
SetAddress(0)
WriteData(0xFF)
try:
while True:
time.sleep(1.0)
except KeyboardInterrupt:
GPIO.cleanup()
ICチップ1番、ページ0、アドレス0に0xFF(全点灯)を設定します。

左上一列が点灯しました。(分かるかな・・・)

ICチップ1番、ページ1、アドレス1に書き込みました。

ICチップ1番、ページ7、アドレス63に書き込みました。

ICチップ2番、ページ0、アドレス0に書き込みました。

ICチップ2番、ページ7、アドレス63に書き込みました。
右下の4ドットは右上に表示するアイコンに対応しています。
なので、LCDを全点灯した場合、右下4ドット分は欠けて見えます。
まぁ、ここまでをまとめると、



こういうことですな。
ここまで分かれば、後はデータさえ用意できれば、いろいろ表示できそうだ。
前回までの状況はこちら。
最新ソースはこちら(gitHub)
https://github.com/takishita2nd/diet-mng
データ一覧画面からデータ入力を行います。
<template>
<div>
<div>
<p id="navi">> <a href="/home">HOME</a></p>
<p id="inputbutton">
<button @click="onClickInput">データ入力</button>
</p>
<table class="weightlist">
<tbody>
<tr>
<th class="date">日時</th>
<th class="weight">体重(kg)</th>
<th class="fat_rate">体脂肪(%)</th>
<th class="bmi">BMI</th>
<th class="edit"></th>
<th class="delele"></th>
</tr>
<tr v-for="data in datalists">
<td class="date">{{ data.date}}</td>
<td class="weight">{{ data.weight}}</td>
<td class="fat_rate">{{ data.fat_rate}}</td>
<td class="bmi">{{ data.bmi}}</td>
<td class="edit"><a href="">Edit</a></td>
<td class="delele"><a href="">Delete</a></td>
</tr>
</tbody>
</table>
</div>
<div>
<weight-input-dialog-component :show="showDialogContent" @update="invokeUpdateList"></weight-input-dialog-component>
</div>
</div>
</template>

入力ダイアログ画面は、すでに作成してあるコンポーネントを流用します。
しかし、この一覧画面から入力した場合は、入力後、リストを更新する必要があります。
なので、入力ダイアログコンポーネントから親コンポーネントで信号を送って、リスト更新処理を走らせるようにします。
入力処理はこんな感じ。
clickAdd: function() {
var self = this;
this.param.contents = this.contents;
axios.post('api/weight/add', this.param).then(function(response){
self.clear();
self.closeModal();
self.$emit('update');
}).catch(function(error){
self.error_flg = true;
self.errors = error.response.data.errors;
});
},
ポイントは、親側(データ一覧画面)側で
<weight-input-dialog-component :show="showDialogContent" @update="invokeUpdateList"></weight-input-dialog-component>
の@update=”invokeUpdateList”の部分。
これがある状態で、子コンポーネントから
this.$emit('update');
を実行すると、親コンポーネントのinvokeUpdateList()メソッドが実行されます。
created: function() {
this.updateList();
},
methods: {
onClickInput: function() {
this.showDialogContent = true;
},
invokeUpdateList: function() {
this.updateList();
},
updateList: function() {
this.datalists = [];
var self = this;
axios.post('api/weight/list').then(function(response){
response.data.dataLists.forEach(element => {
self.datalists.push({
date: element.datetime,
weight: element.weight,
fat_rate: element.fat_rate,
bmi: element.bmi
})
});
}).catch(function(error){
});
}
}
こんな感じで更新処理を行えばOK。
ちなみに、ダッシュボード画面(:@updateの記載がない)に対して$emit(‘update’)を行っても特にエラーにはなりませんでした。
子コンポーネント定義に書かなければ、emitしても何事もなく動くみたいです。

前回までの状況はこちら。
最新ソースはこちら。(gitHub)
https://github.com/takishita2nd/Picross
あれから、いくつかの問題を解いてみましたが、まだまだ不具合が多く、調査・修正しながら解いていきました。
どこを直したかはgitHubのコードを参照して頂きたく。



だいたいここまで攻略できれば、解析処理も一段落できそう。
解析処理は一旦ここまでにして、UI側の修正に戻ろうと思います。
いろいろ弄っていると、UIの挙動にもおかしいところが見受けられたので、その修正を行いたいと思います。

前回までの状況はこちら。

さて、このLCDディスプレイを実際にPythonで動かすのですが。
やっぱり、自分一人の力ではなかなか難しかったので、
こちらのサイトのサンプルソースコードを参考にさせて貰いました。
http://zattouka.net/GarageHouse/micon/Arduino/GLCD/GLCD.htm
こちらはArduinoで使用した物で、ソースコードもC言語に似た独自言語を使用しています。
これをラズパイ/Python用に落とし込みます。
import RPi.GPIO as GPIO
import time
RS_p = 7
RW_p = 8
E_p = 9
CS1_p = 18
CS2_p = 19
DATA_p = [0] * 8
SetPg = 0
SetCol = 0
def PinsInit(rst, rs, rw, enable, cs1, cs2, d0, d1, d2, d3, d4, d5, d6, d7):
GPIO.setmode(GPIO.BCM)
#データピンの番号セット
DATA_p[0] = d0
DATA_p[1] = d1
DATA_p[2] = d2
DATA_p[3] = d3
DATA_p[4] = d4
DATA_p[5] = d5
DATA_p[6] = d6
DATA_p[7] = d7
#制御ピンの番号をセット
RS_p = rs
RW_p = rw
E_p = enable
CS1_p = cs1
CS2_p = cs2
#指定の制御ピンをデジタル出力に設定
GPIO.setup(RS_p, GPIO.OUT)
GPIO.setup(RW_p, GPIO.OUT)
GPIO.setup(E_p, GPIO.OUT)
GPIO.setup(CS1_p, GPIO.OUT)
GPIO.setup(CS2_p, GPIO.OUT)
#指定のデータピンをデジタル出力に設定
for i in range(8):
GPIO.setup(DATA_p[i], GPIO.OUT)
#信号線をLOWに設定しておく
GPIO.output(RS_p, GPIO.LOW)
GPIO.output(RW_p, GPIO.LOW)
GPIO.output(E_p, GPIO.LOW)
GPIO.output(CS1_p, GPIO.LOW)
GPIO.output(CS2_p, GPIO.LOW)
#LCDモジュールのリセットを解除する
GPIO.setup(rst, GPIO.OUT)
GPIO.output(rst, GPIO.HIGH)
ここでは、ラズパイのGPIOの入出力設定と信号線の対応を行っています。
ちなみに、今のブレッドボードでは以下の様に接続されています。

設定が終わったらRSTの信号をHIGHにすることでLCDディスプレイが使用可能になります。
def GLCDInit():
#30ms待機
time.sleep(0.03)
#左側ICを初期化
SelectIC(1)
command(0xC0, GPIO.LOW)
command(0x3F, GPIO.LOW)
#左側ICを初期化
SelectIC(2)
command(0xC0, GPIO.LOW)
command(0x3F, GPIO.LOW)
def SelectIC(value):
if value == 1:
GPIO.output(CS1_p, GPIO.HIGH)
GPIO.output(CS2_p, GPIO.LOW)
else:
GPIO.output(CS1_p, GPIO.LOW)
GPIO.output(CS2_p, GPIO.HIGH)
def command(value, mode):
GPIO.output(RS_p, mode)
for i in range(8):
GPIO.output(DATA_p[i], (value >> i) & 0x01)
GPIO.output(E_p, GPIO.HIGH)
GPIO.output(E_p, GPIO.LOW)
LCDディスプレイの初期化を行います。
ここでは、マニュアルに書いてあるとおりの手順を行います。

このディスプレイはICチップが2枚使用されていて、SelectIC()でコマンドを送信するICチップの番号を設定します。
command()でコマンドを送信します。
第2パラメータはLOW(制御コマンド)、HIGH(表示データ)を選択します。
(もっとわかりやすくした方が良いな・・・)
あと、サンプルを見て気がついたのは、信号をインプットするのに、E信号をHIGHにしなくちゃいけない、ということ。
HIGHでRSやデータ信号が実際にLCDモジュールに入ります。で、終わったらLOWに戻します。

タイミングチャートにしっかり書いてあった・・・
def GLCDDisplayClear():
for i in [1, 2]:
SelectIC(i)
for y in range(8):
SetPage(y)
SetAddress(0)
for x in range(64):
WriteData(0)
def SetPage(value):
command(0xB8|(value&0x07), GPIO.LOW)
def SetAddress(value):
command(0x40|(value&0x3F), GPIO.LOW)
def WriteData(value):
command(value, GPIO.HIGH)
ディスプレイの表示を全て非表示に設定します。(画面クリア)
def __main():
PinsInit(20, 7, 8, 9, 18, 19, 10, 11, 12, 13, 14, 15, 16, 17)
GLCDInit()
GLCDDisplayClear()
try:
while True:
time.sleep(1.0)
except KeyboardInterrupt:
GPIO.cleanup()
__main()
これで、一通りの初期化処理ができました。
データを書き込む関数もあるから、次回はちょっといろいろ表示させてみようか。
