2023年7月30日日曜日

PlatformIOでATTiny13A開発 (AVRISP mk II を使う) [ AVR ]

久々にAVRマイコンを使って開発しようと思ったら!!

世の中の変化にびっくりです。

なんと!AVRのATTiny13Aの価格が!!秋月で150円になってる!!

たしか・・・8年ぐらい前に60円ぐらいで買ったような気が!!

いつの話だよってことですが(笑)


その時、喜んで5個ぐらい買って、1個使って4個は大切にしまわれていました。

そんなこんなで、のんきに暮らしているうちに、AtmelはMicrochipに買収されちゃうし、ATTiny202とかの新しくて良さげなチップが70円で買えるし・・・

なので、ATTiny13Aの在庫整理のために使うことにしたのですが・・・

今どきはATTiny13AもArduinoとして開発できるらしいので、そうすることにする。

で、Arduino IDEは使いづらいので、いろいろ探してたら、流行りは PlatformIOらしいのですよ!!

そういうわけで、VSCode上でPlatformIOを使うことにしたのですが、Arduino UNO とかの USBシリアル変換が載ってるボードは簡単に接続して書き込みできるんだけど・・・

ATTiny13Aは、書き込み装置が別に必要なので、虎の子の AVRISPmkIIを使うことにしたのですが、そのままでは認識しないみたい・・・


検索しても、日本語の記事はあまり見つからなかった。
でも、公式ページにはありました。


まあ、その通りに書けばいいのでしょうが、使うライターはAVRISPmkIIだとわかっているので、自分なりに書いてみました。
ようは、avrudeに渡すパラメータupload_flags で指定すれば良いようです。


platformio.ini
[env:attiny13a] platform = atmelavr board = attiny13a framework = arduino upload_flags = -c avrisp2 -p $BOARD_MCU upload_command = avrdude $UPLOAD_FLAGS -U flash:w:$SOURCE:i

こんな感じになりましたとさ・・・

注意点として upload_flags = の次の行からの オプション指定時にオプション文字の後ろに空白を入れて -c avrisp2 などとすると 空白も名前として含まれてしまうので -cavrisp2 というように続けて書くか、上記のように改行して次の行に書かないといけないようです。




2023年3月3日金曜日

できるかな Python:全角文字でもPython書式を揃えたい [ Python ]

[ できるかな Python ] のコーナー


ここでは実用になるかはさておき、Pythonで出来たら楽しいって事をやってみるだけのコーナーです。

前回前々回と全角文字が揃わない問題を取り扱ってきたのだが!!
とうとう、禁断のクラスを作ることに手を染めてしまった・・・

strをサブクラス化してみるという禁断の手に!!

だって、__format__()とかオーバーライドしてみたいじゃん!

で、割とうまく言ったのだが!!
内部で使った正規表現が。。。いまいち自信ないね(笑)
まあ、動いてるっぽいよ未来の俺!


で、今回のレシピはこれ!

<材料>
  • str型
  • east_asian_width()
  • 特殊メソッド__format__()
  • 特殊メソッド__add__()
  • 特殊メソッド__radd__()

<作り方のポイント>
  • __format__()メソッドで全角文字の時に対応する
  • __add__()および__radd__()をオーバーライドして文字列の結合に対応する
  • east_asian_width()で全角文字を判断する
  • formatを正規表現を使って上手に料理する ※これは保証できない(笑)


stringw.py
from __future__ import annotations # 自分自身のクラスを型注釈できるように(必ずソースの先頭) from unicodedata import east_asian_width from functools import reduce from typing import TypeVar, Generic, Callable import re class StringW(str): @property def length(self) -> int: return len(self) @property def width(self) -> int: # Japanese wide-char size is calculated as 2 bytes. return reduce(lambda a, c: a + 1 + (east_asian_width(c) in "FWA"), self, 0) @property def diff(self) -> int: return self.width - self.length def __add__(self, other: StringW) -> StringW: return StringW(super().__add__(other)) def __radd__(self, other: StringW) -> StringW: return StringW(other.__add__(self)) def __format__(self, format: str) -> str: formatreg = r"((?:\S?[<>=^])?[-+ ]?z?#?0?)(\d*)([_,]?\.?\d*\w?)" m = re.match(formatreg, format) def convert(m): if m[2]: width = int(m[2]) - self.diff if not width < 0: return f"{m[1]}{str(width)}{m[3]}" return m[0] newformat = re.sub(formatreg, convert, format) return super().__format__(newformat)
使い方は、文字列をStringW()に渡して、オブジェクトにするだけ!!
あ〜ら不思議!文字列が崩れることなく、表示されちゃう!!
しかも!Pythonのフォーマットも使えちゃう!!

     
<例>
def example(): member: list[dict[str, str | int | float]] = [ { "user name":"あいうえ", "weight":90, "height":177 }, { "user name":"Super 真理雄", "weight":1250, "height":188 }, { "user name":"Ninja", "weight":70, "height":160 }, { "user name":"Mr.エックス", "weight":66, "height":167 }, ] mr = StringW("こんにちは、Mr.x") mr += "!!" print(mr) print(f"length: {mr.length} width: {mr.width}\n") for m in member: name = StringW(m['user name']) print(f"{name:_<13s} : {m['weight']:>8,.1f}Kg : {m['height']:>5}cm") if __name__ == "__main__": example()

<表示結果>
こんにちは、Mr.x!! length: 12 width: 18 あいうえ_____ : 90.0Kg : 177cm Super 真理雄_ : 1,250.0Kg : 188cm Ninja________ : 70.0Kg : 160cm Mr.エックス__ : 66.0Kg : 167cm

ちなみに、プロパティの length はlen()関数と同じ文字数で、
width全角文字を2とした幅を表していますぞ!

めでたしめでたし!
おお!今日は『ひな祭り』ではないですか!!
めでたい!めでたい!


2023年2月21日火曜日

できるかな Python : 辞書(dict)をプロパティの様に参照したい [ Python ]

[ できるかな Python ] のコーナー


ここでは実用になるかはさておき、Pythonで出来たら楽しいって事をやってみるだけのコーナーです。

Pythonで辞書型を使ってる時に、ついつい、Javascriptのように『.』で参照しようとしてしまうってことあるよね。

ん?ない?
まあ、そういう人もいるでしょう・・・

でも、『 [ "  " ] 』をタイプするのは面倒なことってあるよね。
ん?ない?
じゃあいいです。そういう人はキライです・・・


なので、私は、あるということで話を進めるのです。
何がしたいかというと・・・
member = { "name" : "あいうえ", "height" : 177 }
みたいな辞書があった時に、
Javascriptなら・・・
Javascriptの場合
member["name"] member.name
上記のどちらでも参照できるってことですよ!
Pythonは上の方しかできないんだよね〜

そこで、Pythonも『.』方式で値が取れたら、うれしいなぁと・・・

といっても、やることは簡単なのですが(笑)


では早速、今回のレシピです。

<材料>
  • 辞書型のオブジェクト
  • 特殊メソッド__getattr__()
  • 特殊メソッド__getitem__()

<作り方のポイント>
  • __getattr__()メソッドの利用
  • [ ]でのアクセスもできるように__getitem__()も利用
Pythonで頑張る
from __future__ import annotations from typing import TypeVar, Generic T = TypeVar("T") class Prop(Generic[T]): def __init__(self, param: dict[str, T]) -> None: self.param = param def __getattr__(self, key: str) -> T: if isinstance(key, str): key = key.replace("_", " ") return self.param[key] def __getitem__(self, key: str) -> T: return self.param[key] def main(): members: list[dict[str, str | float | int]] = [ { "user name":"あいうえ", "weight":90.0, "height":177 }, { "user name":"Super 真理雄", "weight":250.0, "height":188 }, { "user name":"Ninja", "weight":70.5, "height":160 }, { "user name":"Mr.エックス", "weight":66.5, "height":167 }, ] for m in members: mem = Prop(m) print(f"{mem.weight:5.1f}cm {mem.height:5d}Kg : {mem.user_name}") print(f"{mem['weight']:5.1f}cm {mem['height']:5d}Kg : {mem['user name']}") if __name__ == "__main__": main()
今回は特殊メソッド__getattr__()を使えば解決です!!
簡単な料理でした。。。。。

Prop()に辞書を渡せば、『.』で参照できるオブジェクトを返してくれます。
は〜い。便利???


ちなみに、スペースはアンダースコアとして参照できるようにしてあります。
いわずもがな、Keyはstr型のみの対応です。。。



以上、腱鞘炎の予防対策でした(終)




できるかな Python : カリー化 [ Python ]

[ できるかな Python ] のコーナー


最近、Pythonにハマってるので、いろいろとやってみた!
ここでは実用になるかはさておき、Pythonで出来たら楽しいって事をやってみるだけのコーナーです。


今日は、関数のカリー化です。
カリー化については、Wikipediaでも見てくださいね。


<材料>
  • 引数を複数とる関数
  • lambda式
  • 特殊メソッド__call__()

<作り方のポイント>
  • __call__()の利用
  • 可変引数の利用
  • 引数展開の利用
  • lambda式の利用
  • 関数呼び出し時の引数エラー(TypeError)例外の利用

カリー化
from __future__ import annotations from typing import Callable class LikeCurry: def __init__(self, func: Callable[..., any]) -> None: self.func = func def curry(self, *args: any) -> Callable[..., any]: return lambda *a: self.func(*args, *a) def __call__(self, *args: any) -> any: try: return self.func(*args) except TypeError: return LikeCurry(self.curry(*args)) def main(): def add3(a, b, c): return a + b + c add3c = LikeCurry(add3) print(add3c(2,3,4)) print(add3c(2)(3,4)) print(add3c(2,3)(4)) print(add3c(2)(3)(4)) if __name__ == "__main__": main()

LikeCurry()に関数を渡すとカリー化された関数風味のオブジェクトを返してくれます。
後は関数っぽく使えば・・・・

はい、おいしく出来ました!!!

何が嬉しいのかって?
それは、人それぞれです(笑)




2023年2月15日水曜日

Python書式:全角文字の幅問題(完成のつもり) [ Python ]

前回のつづき「全角文字も揃えたい」です。
がんばっちゃったよ(笑) 暇ともいうが・・・

 Pythonの書式で%sの幅指定が文字数でカウントされるので、文字幅が全角と半角が混在すると全角分ずつずれてしまう問題の解決策をここに書いておくよ!将来の自分のために・・・

で、完成版です、はいこれ!

文字幅の指定を負数にすると左寄せになるのです!


<追記>ついに、禁断の手に出たぞ俺!


member.py
from unicodedata import east_asian_width from functools import reduce member = [ { "name":"あいうえ", "weight":90, "height":177 }, { "name":"Super 真理雄", "weight":250, "height":188 }, { "name":"Ninja", "weight":70, "height":160 }, { "name":"Mr.エックス", "weight":66, "height":167 }, ] padstr = lambda s,w: reduce(lambda a, c: a[east_asian_width(c) in "FWA" and 2 or 1:]+c, s[::(w < 0) and -1 or 1], " "*abs(w))[::(w < 0) and -1 or 1] print("<< padstr(+) >>") for m in member: print(f'{padstr(m["name"], 15)} : {m["weight"]:5}Kg {m["height"]:5}cm') print("-"*50) print("<< padstr(-) >>") for m in member: print(f'{padstr(m["name"], -15)} : {m["weight"]:5}Kg {m["height"]:5}cm')
はい、めっちゃ長いラムダ式になっちまいました。。。。
もう、普通の関数でいいじゃん。。。

まあ、将来の私よ!
今の私の実力はこの程度なのだよ!!
笑ってくれ(笑)


※ちなみに、ラムダ式を変数に代入することはPEP8の推奨事項を無視することになります(笑)


<追記>
んで、もうちょっと短くしてみた・・・

関数のところだけ抜粋・・・

<追記>
コピペ版用にimportも追加しておく
あ、文字幅は 日本語1文字 を としてネ!

最終版?
from unicodedata import east_asian_width from functools import reduce padstr = lambda s,w: reduce(lambda a,c:a[(east_asian_width(c)in"FWA")+1:]+c,s[::abs(w)//w]," "*abs(w))[::abs(w)//w]
よく出来ました。

でも、超読みづらい!!!

おしまい。。。




2023年2月12日日曜日

Python書式:全角文字の幅問題 [ Python ]

いやー、久しぶりにPythonやってみましたよ。
プログラミングたのしいね〜!

今回、print()関数で文字を揃えようと思って、"%-15s"みたいな書式を指定したわけですよ!!
そうしたら、なんと!
全角と半角が混在していると、見た目が崩れてしまう問題がはっせい!!

全角文字幅が1文字扱いのようです!!!

「全角文字も揃えたい」ですよね〜


<<追記>>


member.py
member = [ { "name":"あいうえ", "weight":90, "height":177 }, { "name":"Super 真理雄", "weight":250, "height":188 }, { "name":"Ninja", "weight":70, "height":160 }, { "name":"Mr.エックス", "weight":66, "height":167 }, ] for m in member: print("%-15s : %5dKg %5dcm" % (m["name"], m["weight"], m["height"]))
全角文字揃えが崩れちゃう
あいうえ : 90Kg 177cm Super 真理雄 : 250Kg 188cm Ninja : 70Kg 160cm Mr.エックス : 66Kg 167cm

困りました!てなわけで、世の中の人に聞いてみると!!
note.nkmk.meさんが教えてくれていました!感謝ですな★

なんと!unicodedata.east_asian_width()を使うと素敵になれるようです!

ただ、この関数は全角・半角というのを直接教えてくれるわけではないのです。
いろいろ複雑な事情があるようです・・・
まあ、そこは良いとして、とにかく "F" "W" "A" なら全角、それ以外なら半角ということで判断しましょう!!

よって、全角文字なら幅をもう1文字分必要とするように引き算してやればOKですな!
member.py
from unicodedata import east_asian_width from functools import reduce member = [ { "name":"あいうえ", "weight":90, "height":177 }, { "name":"Super 真理雄", "weight":250, "height":188 }, { "name":"Ninja", "weight":70, "height":160 }, { "name":"Mr.エックス", "weight":66, "height":167 }, ] for m in member: name_w = reduce(lambda a, c: east_asian_width(c) in "FWA" and a-1 or a, m["name"], 15) print("%-*s : %5dKg %5dcm" % (name_w, m["name"], m["weight"], m["height"]))
すばらしい!そろってる!
あいうえ : 90Kg 177cm Super 真理雄 : 250Kg 188cm Ninja : 70Kg 160cm Mr.エックス : 66Kg 167cm

じゃじゃ〜ん!!
素敵になりました!!!

forループとか書くとコードが長くなるので、reduce()を使いました。
これは、functoolsモジュールに入ってます。(python2の頃は組み込み関数だったらしい)

reduce()の行はちょっとゴチャッとしてますが、一行でかけるので、コードの流れがスマートになって良いと思います。(自画自賛)


ポイントは、書式幅も引数(タプル)で指定してやることですぞ!
"%-*s"の"*"が肝です!!


あっ!今気づいたけど、サンプルコードの身長と体重の書式を整数にしてしまった・・・
まあいいや。なおすのめんどい・・・・


もうちょっとすすめて、ラムダ式で関数にしてみた。

member.py
from unicodedata import east_asian_width from functools import reduce member = [ { "name":"あいうえ", "weight":90, "height":177 }, { "name":"Super 真理雄", "weight":250, "height":188 }, { "name":"Ninja", "weight":70, "height":160 }, { "name":"Mr.エックス", "weight":66, "height":167 }, ] withw = lambda s,w:(reduce(lambda a, c: east_asian_width(c) in "FWA" and a-1 or a, s, w), s) for m in member: print("%-*s : %5dKg %5dcm" % (*withw(m["name"], 15) , m["weight"], m["height"]))

このほうが使いやすいな!
ポイントは、このwithw()関数 がタプル ( 文字幅 ,  文字列 ) を返すので、で展開してやるのだ!

う〜ん。まんぞく!
めでたしめでたし!!



<追記>
いやいや、よく考えたら文字幅分をスペースで埋めとけば良かったんじゃね?
アホでした。

member.py
from unicodedata import east_asian_width from functools import reduce member = [ { "name":"あいうえ", "weight":90, "height":177 }, { "name":"Super 真理雄", "weight":250, "height":188 }, { "name":"Ninja", "weight":70, "height":160 }, { "name":"Mr.エックス", "weight":66, "height":167 }, ] padstrl = lambda s,w: reduce(lambda a, c: c+a[:east_asian_width(c) in "FWA" and -2 or -1], s[::-1], " "*w) padstrr = lambda s,w: reduce(lambda a, c: a[east_asian_width(c) in "FWA" and 2 or 1:]+c, s, " "*w) for m in member: print(f'{padstrl(m["name"], 15)} : {m["weight"]:5}Kg {m["height"]:5}cm') print("-"*50) for m in member: print(f'{padstrr(m["name"], 15)} : {m["weight"]:5}Kg {m["height"]:5}cm')

前回のwithw()関数の場合はPythonの書式の方で左寄せと右寄せを指定できたけど、
今回のラムダ式で左寄せと右寄せを一つの式にするのは、
俺の頭では短くかけないので、2つに分けた!


ちなみに、f"" 書式のこともすっかり忘れてました(汗)




ふんどしの持ち主

2022年12月13日火曜日

Kubuntu22.04 中クリックを無効にしたくないけどする

最近Kubuntuに環境を移行してから、ほとんどの作業をこれで行っているのです。

なんと行っても、Visual Studio CodeがKubuntu上でも動くのが大きいですな。でも、Illustratorは動かないので、完全にKubuntuに移れない、それだけが残念ではある。

そうそう、元々はVSCodeではなく、Brakets使ってたんだけど、開発終了しちゃったのでVSCodeに移ったのですよ。


で、Thinkpadで作業をしていると、どうしてもスクロールに中クリックを使うのだけれども、こいつが、ペーストの機能も持っているので、相性が悪いのです。

この中クリックのペーストは地味に便利なので無効化したくないんだけどね。プロセスをkillするときにPIDをペーストするときとか大活躍ですよ(笑)

しか〜し、VSCodeとかでコーディング中にスクロールするつもりで中クリックを軽く押してしまって、ペーストされちゃうと、ちょ〜がっかりです。まあ、トラックポイント使わずキーボードだけで書けよって話ですが、トラックポイントはちょ〜便利なので、ついつい手が伸びちゃうんだよね〜。

なので、中クリックを泣く泣く無効化しようという話です。

なんと、virtualimentさんが教えてくれてますよ。ありがたや〜。

厳密には同じじゃないけど、virualimentさんの記事に従えば簡単ですな。

$ xinput list
⎡ Virtual core pointer                           id=2    [master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer                id=4    [slave  pointer  (2)]
⎜   ↳ Elan Touchpad                             id=11   [slave  pointer  (2)]
⎜   ↳ Elan TrackPoint                           id=12   [slave  pointer  (2)]
⎣ Virtual core keyboard                          id=3    [master keyboard (2)]
    ↳ Virtual core XTEST keyboard               id=5    [slave  keyboard (3)]
    ↳ Power Button                              id=6    [slave  keyboard (3)]
    ↳ Video Bus                                 id=7    [slave  keyboard (3)]
    ↳ Sleep Button                              id=8    [slave  keyboard (3)]
    ↳ Integrated IR Camera: Integrate           id=9    [slave  keyboard (3)]
    ↳ Integrated Camera: Integrated C           id=10   [slave  keyboard (3)]
    ↳ AT Translated Set 2 keyboard              id=13   [slave  keyboard (3)]
    ↳ ThinkPad Extra Buttons                    id=14   [slave  keyboard (3)]

こんな感じでした。ウチの環境では"Elan TrackPoint"となってますな。

2番めを無効化すれば良いらしいので、

$ xinput set-button-map "Elan TrackPoint" 1 0 3 4 5 6 7
$ xinput get-button-map "Elan TrackPoint"
1 0 3 4 5 6 7

素晴らしい!完璧です。中クリックペーストは諦めて、スクロール重視になりました。めでたしめでたし★


最後に、永続化のためにprofileに書いておきましょう!
私の場合はユーザを切り替えて使っているので、グローバルに適用できるように/etc/profileに書いて置くことにします。

/etc/profile
... <省略> ... if [ -d /etc/profile.d ]; then for i in /etc/profile.d/*.sh; do if [ -r $i ]; then . $i fi done unset i fi xinput set-button-map "Elan TrackPoint" 1 0 3 4 5 6 7

ふんどしの持ち主