ラベル プログラミング の投稿を表示しています。 すべての投稿を表示
ラベル プログラミング の投稿を表示しています。 すべての投稿を表示

2026年4月6日月曜日

力こそパワー

↑blog を読み込ませて AIで生成w  日本語がシュールwww

■動機

PS1 の ZEUS: カルネージハート セカンド (以下 CH) というゲームがあって (ゲームの詳細は過去の blog 参照),CH の OKE ソフトのプログラミングはチップを並べる事によって行うので,編集作業が大変.
で,OKE ソフトをプログラミング言語で組めたらいいなぁとずっと思っていたので,やってみた.目的はもう一つあって,AI に聞きながら,もしくはコード生成を丸投げしてどこまでのことができるのか試したくなった.

というわけで OKE Chip Compiler (okecc) プロジェクト開始.ちなみに Github で公開してます.

■AI の威力

okecc のやるべきことは 2つ.言語から CH のチップ群に変換する言語パーサと,チップを処理の流れに従って矛盾なく並べる配置処理.前者は過去経験があるので良いとして,後者をどうやったらいいのか見当もつかないので,AI に聞いてみる.

  • MxN のグリッドにチップを並べる問題を解くアルゴリズム
  • チップの接続関係はすでに定義されている
  • チップは縦横斜めの 8方向に隣接したチップと接続できる
  • それ以上離れている場合は NOP チップで接続する.
  • MxN のグリッドに全チップを並べ,NOP 数を最小化することがゴール.

という問題を与えてみたところ,最初は巡回セールスマン問題とかずれた回答をしていたが,こちらが補足として CH の名を出したとたん AI の理解が急速に進み,CH の内容を正しく理解していることにびっくり.それでいくつかアルゴリズムの案をだしてきた.

  • この問題をグラフ理論とみなして既知のアルゴリズムを適用: CH の離れたチップは NOP チップで接続する必要があり,つまり配線スペースが必要だが,既知のアルゴリズムではそれは考慮されないという課題あり
  • 機械学習: 教師データの準備が大変という課題あり
  • 焼きなまし法: AI のおすすめ.全数探索が不可能な問題はとりあえずこれだそうで.

ここでダメ元で「焼きなまし法のコードを出して」とお願いしたら,それなりに動くコードが出てきてまたびっくり.焼きなまし法はおぼろげな知識はあるが,正確なやり方は知らなかったので,実際に動くコードがあるのと無いとでは自分の理解が断然違う.AI が吐いた最初期のコードだけでも下図のようなまともな配置を吐くことができて,このプロジェクトが成功する手応えを得た.

ちなみにこれ,SVG で出力したものを Web ブラウザで表示していて,SVG 出力のコードはは 100% AI が吐いてくれた.こういった,誰かがもうやっているであろうコードを吐くのは AI は得意そう.

■AI の限界

上の配置図は一見まともだが,黄色の箇所とか配置がおかしく,正解ではない.

ここで焼きなまし法の流れを簡単に説明すると,以下のようになっている.

  1. 今のチップ配置を元に次のチップ配置を生成する.ランダムに 1チップ選び,高確率で隣接するチップと入れ替えるか,低確率でランダムな場所とスワップする.
  2. チップ配置のスコアを計算する.接続するチップが離れていたら離れているマス数分のペナルティ,またそのチップ間のパスが他のチップ上を通過していたら大ペナルティ
  3. 前回のチップ配置からスコアが良化すれば新しいチップ配置を採用,スコアが悪くても確率で採用するが,解の探索が進むごとにその確率は少なくしていく.

で AI が吐いたコードは色々課題があって,

  • 解けない配置にハマると,一度スコアが悪い状態を経ないと正解にはたどり着けないが,その頃には「スコアが悪くても確率で採用」の確率が低くなっているため,スコアが悪い状態を許容出来ない
  • そうなってしまう主な理由は,次のチップ配置の生成がランダム要素が強く,スコアが良化する配置が生まれにくいため,良い配置に収束するのに時間がかかりすぎているため

という問題があることがわかった.そこの問題点を指摘して AI にコード吐かせてみたが,たいして効果が無かったり,的外れであったりと,この時点では AI はさほど有用ではなかった.
CH のチップ配置という誰もやったことがないことに対しては,どこにも参考となるコードがないから,AI もまともな回答はできないようだ.このあたりが AI の限界だなぁと悟った次第.

■力こそパワー

で「より良い配置を生みだしやすくする配置生成アルゴリズム」は結局のところ人間の力で考えるしか無いが,アルゴリズムさえ考えて指示すれば,AI はちゃんとコードを吐いてくれる.
そうしたアルゴリズムを追加していった結果,チップ数が多い場合でも数十回に 1回ほど配置が成功するようになったので,後はマルチスレッド + 正解するまでループ,の力技で正解を探索するようにした.結局最後は CPU パワーがすべてを解決するw

ようやく実用的なものが出来たヽ(´ー`)ノ

今回 AI を活用してソフトを開発してみた感想としては,AI は「ネット上の膨大な知識を持っている社外工」だと感じた.
例えば最新 C++ の書き方を教えてくれたり,あと PS1 メモリカードイメージファイルから,特定のゲームのセーブデータを抜き出すコードなんかも一発で書いてくれた.
ただし誰もやったことがないことをアルゴリズムレベルまで落とし込むのはまだまだ人間の仕事で,そこら辺は考えてくれないところが社外工っぽい.あとまれに間違ったコードを吐いたりもするので,そこの W チェックが必要なのも,社外工と仕事やってる感覚と似てるなぁと思った.

2025年12月16日火曜日

u-blox M10 測位頻度改善

ちょっと前に買った中華激安 GPS ロガーに載っている u-blox M10 という GNSS チップ,公称 10Hz で測位できるはずだが,測位してから数分経つと測位頻度が 6-8Hz 程度に低下することに気づいた.
不思議なことに室内での実験ではなかなか再現せず,車内 & 自作 Android アプリで頻発するので,自作 Android アプリの問題かと思ったが,PC <--> GPS ロガーでも測位頻度が低下していることを確認.
ということでこの GPS ロガーの実力であることが確定(;´д⊂)

改めて M10 のデータシートを眺めてみると,

  • 測位処理は MCU が行っており,捕捉する衛星数が多いと更新頻度が落ちる
    • アジア地域は BeiDou (中国のやつ) が多いので測位頻度は落ちがち
  • High Performance Mode という MCU クロックを上げる設定を行うと,測位頻度は上げられる

らしい.

まずは High Performance Mode に設定してみたが,見た感じ変わってなさそう.
あんま変わらなかったのでやり方は詳しくは書かないが,ここの P13 に書いてある.

で次なる作戦.

  • BeiDou を無効化する.これだけで捕捉衛星が 3/5 くらいになる.
  • 不要な NMEA センテンス出力を無効化する
  • ただし自作アプリ以外ではそれらを無効化しないほうが良いので,本体 Flash への設定は行わず,電源 On の間だけ有効な設定にする

そのための設定は割と簡単で,UBX protocol なるものが公開されていて,適切なバイナリデータを Bluetooth 経由で書き込めば良い.
詳しくはこれを見れば全部載っている.GGA, GSA, GSV センテンスを止めて,BeiDou を使用しない設定をする Kotlin コードはこんな感じ.

で実際にやってみた結果,10Hz 出たヽ(´ー`)ノ
あと BeiDou を無効化することによる測位精度がどうなるか調べた結果 (上図の青: BeiDou 有り,橙: 無し),全く問題なかった.
BeiDou 有りの方はやはり所々ポイントが抜けているのが気になる.この座標情報からラップタイムを計算するから,ポイントが抜けていないほうがいいので,BeiDou 無しで運用することにした.

2024年11月16日土曜日

Tuya スマートプラグを PowerShell で制御する

前回ブラウザからスマートプラグを制御したとき,URL の情報が見えていたので,後は HTTP リクエストを送れさえすれば制御は余裕と思っていたらそうではなかった.
リクエスト送信前に署名鍵を Tuya から取得し,その鍵で送信するリクエストデータの署名を作成し送信しないとだめっぽい.

で探してみたら,すでに Unix shell から制御するコードはあったので,ありがたくこれを PowerShell に変換してみたのが一番下のコード.

ハマったポイントは,

  • UNIX Time を秒数で得る命令 (Get-Date -UFormat %s) はタイムゾーン分の誤差が発生する (PowerShell のバグっぽい) ので,タイムゾーンオフセット分増減が必要.
  • 署名を作るために必要な Client Secret (Tuya developer サイトから取得する) は 16進32桁なので,128bit の数値だと思ったら,これはそのまま文字列データとして 256bit の数値として扱わないと,Tuya 側で有効な署名と認められなかった

でやった結果.Powershell で 10秒毎に消費電力を取得してみた.なかなか安価で消費電力のログ取れる環境は無いので,これはかなり満足度が高いヽ(´ー`)ノ

以下 PowerShell コード.

2024年11月10日日曜日

Tuya スマートプラグを PC から制御する

大昔にスマートプラグ (ネットワーク経由で On/Off できるコンセント) を買ったけど,独自の Android アプリでしか On/Off できなかったので,あまり使い道がなく放置していた.
で,最近これは Tuya という IoT プラットフォームに準拠した製品であることがわかったので,PC から制御してみた.
ところが Tuya のチュートリアル通りにやっても画面が説明と異なる等多々あり進まなかったので,自分でうまく行った手順を以下に記載しておく.

【開発者アカウント作成・デバイスのリンク】

●まずはスマートプラグと,Android の Smart Life アプリとの連携を済ませておく.

Tuya developer でアカウント作成

●Cloud → Create Cloud Project をクリック

●Create Cloud Project 画面で
  • Project Name: てきとう
  • Industry: Smart Home
  • Development: Smart Home
  • Data Center: データが保存されるサーバの場所? よくわからないがとりあえず Western America Datacenter
にして Create クリック

●Configuration Wizard はそのままで Authorize をクリック

●Devices → Link App Accout → Add App Account をクリックすると,QR コードが表示される

●Android の Smart Life アプリ右上の「+」 → QR コードをスキャン,をタップ後,PC の QR コードを読み込む

●Android アプリの「ログインを確認」をタップ

●以下のような画面が出てくるので,そのまま OK.これで Tuya developer アカウントとデバイスがリンクできた.

【デバイスを PC から制御する】

●どんな操作ができるか (コマンドがあるか) 調べてみる.
ここで表示されている Device ID が後々必要なので控えておき,Devices → All Devices → Debug Device をクリック

●Device Debugging をクリック.
Standard Instruction Set を見ると,使用できる設定系のコマンドがわかる.うちのだと,switch_1 / switch_2 で 2個あるコンセントの On/Off, countdown_n は秒数を設定するとその時間経過後に On/Off を反転する.

Standard Status Set を見ると,状態取得系のプロパティがわかる.うちのだとコンセントの On/Off 状態や,現在の電力が取得できる.

●Cloud → API Explorer をクリック

●Device Control の左の▶をクリック,Send Commands をクリック.

  • device_id: 先程調べた Device ID
  • code: switch_1 など
  • value: true, false など
で Submit Request をクリックすると,スマートプラグが On/Off される.
ここで,Request URL / Response をみると,どういうリクエストを送ればいいかが一発でわかるので,後は好きな言語で好きなように制御できる.もう少し手順が必要

●Get the status of a single device を実行すると,上の Standard Status Set で調べたプロパティが取得できる.

【最後に】

このスマートプラグ,電力計が付いていたので買ったものだが,電力見るのも専用アプリだけでログも取れないので放置していたが,これからは PC でログ取りできるので,かなり使えるアイテムになったヽ(´ー`)ノ

2024年3月24日日曜日

C++ で構造化アセンブリプログラミング

動機

原始的なアセンブラしか無い原始的な CPU のプログラミングをすることになった.
でアセンブリプログラミングの一番の萎えポイントとして,例えば C 言語だと
if(a == b){
  c = d;
}else{
  e = f;
}
みたいに書けるところが,構造化記述できないアセンブラだと
  cmp a, b
  jnz label0
  mov c, d
  jmp label1
label0:
  mov e, f
label1:
とラベルやら分岐命令やら,自分で生成しないといけないのでめんどくさいし,if がネストすると可読性も悪い.真面目にやるなら bison/flex とかでまともな構造化アセンブリ言語を設計するところだけど,そこまでやるのはなぁ... と思ったところで,C++ のクラス / 演算子オーバーロードをうまいこと使えば,構造化アセンブリプログラミングもどきが出来るのでは? と思った.
例えば,C++ で "r0 = r1;" と書いてコンパイル・実行すれば,"mov r0, r1" というテキストが得られる,みたいなイメージ.

まずは代入演算

//////////////////////////////////////////////////////////////////////////////
// Register

class RegisterObject {
public:
  RegisterObject(const char* szName) : m_szName(szName){}
  const char *Name(void) const {return m_szName;}
  
private:
  const char* m_szName;
};

class GpReg : public RegisterObject {
public:
  GpReg(const char* szName) : RegisterObject(szName){}
  
  GpReg& operator=(const GpReg& src){
    printf("\tmov\t%s, %s\n", Name(), src.Name());
    return *this;
  }
};

//////////////////////////////////////////////////////////////////////////////
// Register インスタンス

GpReg r0("r0");
GpReg r1("r1");
GpReg r2("r2");
GpReg r3("r3");

//////////////////////////////////////////////////////////////////////////////
// アセンブリプログラム

int main(int argc, char **argv){
  r0 = r1 = r2;
  return 0;
}
GpReg class は汎用レジスタをイメージしていて,特殊なレジスタがあれば RegisterObject か GpReg を継承する感じ.C++ ソースコード上の変数名 (r0 とか) は実行時には失われてしまうので,m_szName に変数名をセットしておく.
代入演算のキモは言うまでもなく "operator=" で,= が呼ばれたら mov 命令のテキストを出力する.
で実行結果:
        mov     r1, r2
        mov     r0, r1
おお,いい感じ.アセンブラだと r0 = r2 が直接代入できないので一旦 r1 を経由する,みたいなケースが多々あるが,それが 1行で書けるのはありがたい.

比較演算

次に,if-else-endif の構造化をやる前に比較演算子を定義する.
対象 CPU は,== なら cmpeq みたいに比較演算子毎に比較命令があり,その結果をフラグレジスタ f0 にセットする.条件分岐命令は f0 の値をみて分岐するかどうか決める.
class FlagReg : public RegisterObject {
public:
  FlagReg(const char* szName) : RegisterObject(szName){}
};

//////////////////////////////////////////////////////////////////////////////
// Register インスタンス

FlagReg f0("f0");

//////////////////////////////////////////////////////////////////////////////
// global な operator

FlagReg& operator==(const GpReg& a, const GpReg& b){
  printf("\tcmpeq\t%s, %s, f0\n", a.Name(), b.Name());
  return f0;
}

//////////////////////////////////////////////////////////////////////////////
// アセンブリプログラム

int main(int argc, char **argv){
  r0 == r1;
  return 0;
}
RegisterObject を継承して FlagReg を定義する. operater== で,== が呼ばれたら cmpeq 命令を出力して,== の返り値として f0 を返す.
で実行結果:
        cmpeq   r0, r1, f0
これはなんの問題もない.

if-else-endif

そしてこの取り組みの一番の目的である,if-else-endif の構造化をやってみる.
//////////////////////////////////////////////////////////////////////////////
// 構造化構文

int g_LabelCnt = 0;
std::vector<int> g_Label;

void _if(FlagReg& f){
  printf("\tjnset\t%s, _L%d\n", f.Name(), g_LabelCnt);
  g_Label.push_back(g_LabelCnt);
  ++g_LabelCnt;
}

void _else(void){
  printf("\tjmp\t_L%d\n", g_LabelCnt);
  printf("_L%d:\n", g_Label[g_Label.size() - 1]);
  
  g_Label.pop_back();
  g_Label.push_back(g_LabelCnt);
  ++g_LabelCnt;
}

void _endif(void){
  printf("_L%d:\n", g_Label[g_Label.size() - 1]);
  g_Label.pop_back();
}

//////////////////////////////////////////////////////////////////////////////
// アセンブリプログラム

int main(int argc, char **argv){
  _if(r0 == r1);
    r0 = r2;
  _else();
    r1 = r3;
  _endif();
  return 0;
}
_if ではフラグレジスタを受取り,必要な分岐命令を生成する.また if-else-endif はネストするので,分岐先ラベルの情報はスタックに push / pop する必要がある.
で実行結果:
        cmpeq   r0, r1, f0
        jnset   f0, _L0
        mov     r0, r2
        jmp     _L1
_L0:
        mov     r1, r3
_L1:
おおぉ,これこれ! これがやりたかったんだよ.この時点でこのやり方はかなりうまくいく感触を得ていたが,念の為 if がネストするケースをテストしてみたら,
コード:
//////////////////////////////////////////////////////////////////////////////
// アセンブリプログラム

int main(int argc, char **argv){
  _if(r0 == r1);
    _if(r1 == r2);
      r2 = r0;
    _else();
      r3 = r1;
    _endif();
  _else();
    r1 = r3;
  _endif();
  return 0;
}
実行結果:
        cmpeq   r0, r1, f0
        jnset   f0, _L0
        cmpeq   r1, r2, f0
        jnset   f0, _L1
        mov     r2, r0
        jmp     _L2 ←※ここ
_L1:
        mov     r3, r1
_L2:
        jmp     _L3
_L0:
        mov     r1, r3
_L3:
んー,間違いではないんだけど,jmp _L2 の飛び先は jmp _L3 しか無いので,最適化の観点では「ここ」で jmp _L3 にすべき.
この最適化をやるためには,直接アセンブリテキストを出力するのではなく,一旦中間言語とかでメモリ上に溜めておき,最後に最適化フェーズを流す,等しないといけないということがわかった.
それを解決して,あとはメモリアクセスとかラベルへのサブルーチンコールとかを実装すれば,普通に使えそう.

2022年11月23日水曜日

Win11のブートOS選択タイムはわずか0.05秒に過ぎない。ではOS選択プロセスをもう一度見てみよう。

ずっと前に宇宙刑事の蒸着並みに素早く PC をシャットダウン,再起動等できるスクリプトを作って使用していたが,これに OS 選択・ブートデバイス選択・UEFI セットアップ起動 機能を付けたら便利だと思った.
で,やってみる.以下のコマンドはほとんど管理者モードでしか機能しないので注意.

●boot デバイスの選択
bcdedit /enum all の「ファームウェアのブート マネージャー」にブート可能なデバイスの ID 一覧が列挙されている.その ID が具体的に何なのかは,description を見ればだいたい分かる.

C:\Users\yoshi>bcdedit /enum all

ファームウェアのブート マネージャー
--------------------------------
identifier              {fwbootmgr}
displayorder            {f1255e61-6696-11ed-bf20-806e6f6e6963}
                        {c16a79f0-67b4-11ed-bf38-806e6f6e6963} ---+
                        {0d22d0c4-5a00-11ed-bed1-806e6f6e6963}    |
                        {f5f177c6-6ad7-11ed-bf4c-806e6f6e6963}    |
                        {f5f177c7-6ad7-11ed-bf4c-806e6f6e6963}    |
                        {f5f177c8-6ad7-11ed-bf4c-806e6f6e6963}    |
timeout                 0                                         |
                                                                  |
ファームウェア アプリケーション (101fffff                         |
--------------------------------                                  |
identifier              {0d22d0c4-5a00-11ed-bed1-806e6f6e6963}    |
device                  partition=\Device\HarddiskVolume1         |
path                    \EFI\MICROSOFT\BOOT\BOOTMGFW.EFI          |
description             Windows Boot Manager                      |
                                                                  |
ファームウェア アプリケーション (101fffff                         |
--------------------------------                                  |
identifier              {c16a79f0-67b4-11ed-bf38-806e6f6e6963} ←-+
device                  unknown
description             UEFI: Generic-Multi-Card 1.00, Partition 1
bcdedit /set {fwbootmgr} bootsequence {デバイスのID}
shutdown /r /t 0

を実行すると,再起動後に指定したデバイスがブートする.

●マルチブート OS の選択
BCD でマルチブートを構成している場合,bcdedit /enum all の「Windows ブート マネージャー」にブート可能な OS の ID 一覧が列挙されている.

その ID が具体的に何なのかは,description を見ればだいたい分かる.で

bcdedit /bootsequence {ID}
shutdown /r /t 0

を実行すると,再起動後に指定した OS がブートする.

●UEFI setup 起動

shutdown /r /t 0 /fw

を実行すると,再起動後に UEFI セットアップが起動する (はず).

で powershell でスクリプト組んで作ってみた.で使ってみたら我ながら超便利.
UEFI setup のための [DEL] キー連打に失敗してストレスが溜まる,なんてことが皆無だし,ブート OS 変更のために何回もマウスクリックしてたのが一発だし.超快適ヽ(´ー`)ノ

というわけで以下 powershell のコード.

2022年5月4日水曜日

Selenium Chrome / Edge driver 更新を自動化する

 自分は Selenium + PowerShell でいろいろ Web 操作を自動化しているが,Chrome / Edge の自動 Update に合わせて Chrome / Edge Driver も更新しないと,スクリプト実行時にエラーで停止してしまう.
(Edge はよく知らないけど) Chrome は結構頻繁に更新されてしまうので,Driver も自動更新させてみた.

Chrome / Edge / Edge Driver のバージョンは exe のリソースに埋め込まれているので,

(get-item ("ファイル")).VersionInfo.FileVersion
で取得できる.Chrome driver は exe リソースにバージョン番号が記録されてないので,適当なテキストファイルに Driver バージョンを記録して,次回はそれを参照することにする.

あとは,Chrome / Edge と Driver のメジャーバージョン番号が異なっていれば,Invoke-WebRequest で Driver をダウンロードして zip 展開すれば良い.

というわけで,以下コード.これを Selenim を使用する PowerShell スクリプトの先頭で

. "selenium.ps1" # インクルード
UpdateDriver('chrome') # または 'edge'
とすることで Driver を自動で Update できた.

2021年8月19日木曜日

Python で Android アプリ開発 (もどきに戻る)

今までのあらすじ:
・Android で Python/kivy スクリプトを動かしたい
・スクリプトを実行するためには Pydroid 3 起動,スクリプトをエディタで開く,実行 の 3ステップが必要でめんどい
・apk 化したら起動は楽だがスクリプトの利点が削がれる ←いまここ


で Github を色々探してみると,Kivy-Launcher というアプリ発見.これは Python スクリプトのリストを表示して,選択・実行できる.これも Python/kivy/buildozer で実現されており,ということはこの環境でストレージ上の Python スクリプトを実行する手段はあるということ.

次に,buildozer でビルドしたアプリに暗黙的インテント (Windows で言うところの拡張子関連付けみたいな情報をアプリ側に持たせる) を追加する手段があるか探してみたところ,あったよ... この時点で勝利を確信ヽ(´ー`)ノ

というわけで以下を実施.
・Kivy-Launcher を fork
・暗黙的インテントを追加
・起動直後のインテント解析等を行う python スクリプト (main.py) は,このままだと apk に内蔵されてしまい修正がめんどくさいので,main.py から SD カード上の main.py を呼ぶように修正し,起動後のスタートアップ処理は後者で処理する

適当なアプリで Python スクリプトへのショートカットを作り,これをタップするだけでスクリプト起動した.

更に main.py を SD カード上に置いたことにより色々やりやすくなり,例えば標準だと Python のエラーメッセージは adb logcat でしか見れない (PC と 要 USB 接続) が,main.py で try~exception でエラーをキャッチしてメッセージを画面上に表示することで,スマフォ単体でエラーが確認できるとか,色々改良しやすい.

やっとことさ理想の環境を手に入れたよヽ(´ー`)ノ

2021年8月18日水曜日

Python で Android アプリ開発 (もどきではない)

前回の記事で「Python + kivy で普通の Android アプリも開発できそう」と書いたけど,自分が知らなかっただけで,それは割と普通のことらしい.つまり Python スクリプトを apk 化する buildozer なるツールもあって,これを使えば Python スクリプト起動の手間の問題は解決する.ただ自分が Python を使いたいのはそういう apk ビルドの手間・ビルド環境の構築を省きたいからであって,ちょこっとスクリプトを修正して実行確認,みたいに手軽にやりたい.

ここで,Github Actions を使えば手間は減らせるんじゃね? 思った.Python 開発・デバッグは PC 上で行い,完了したらどのみち Github には push するので,それをトリガに Github に自動で apk ビルドをさせると.
というわけでやってみた.

・.github/workflows/build.yml をここからもらってくる
・buildozer.spec をここからもらってくる
・上記を適当に修正する
・SD カードアクセス等の,必要なパーミッションを追加する
・git push する

たったこれだけで出来たヽ(´ー`)ノ 普通の apk と何ら変わりなくインストール・起動も出来て,動作は apk 化する前と全く同じ.

普通の Android アプリを Java で書くのは色々めんどくさいけど Python + kivy はほんとにお手軽で書きやすい.しかもこれだけの労力・学習コストで「俺 Android アプリ作って公開してるんだぜ(ドヤァ」って言えるのはすごいwww

これからは特に問題ない限り,Android アプリは Python + kivy で開発しようと思った.

2021年8月15日日曜日

Python で Android アプリ開発もどき

出先で Android で GPS ログフォーマットを変換したい.処理的に大したことなくまた PC でも使いたいので perl とかで書きたいが,問題はスクリプト起動時に Android でコマンドライン入力するのは地獄.
なのでファイル選択やオプション選択などを GUI で操作したいが,そんな事ができる Android アプリがないか探してみたところ,Pydroid 3 というアプリ発見.
基本的には Python 実行環境だが,kivy という GUI を構築できるフレームワーク(?) が内蔵されていて,これを使って簡単な GUI アプリが構築できる.

というわけで作ってみた.→GitHub
画面の要素としてはファイル選択とリストボックス,ボタンと簡易.見た目はしょぼいが実用性は十分.Python + kivy 自体はそこそこ実用的で,Android ハードにバリバリアクセスするようなアプリでなければ普通のアプリでも開発できてしまうと思う.

あと,kivy 自体はクロスプラットフォームなので,全部 PC 上で開発・デバッグ後 Andoid で運用する,等もできるので,開発効率はよい.

ただ残念なのは,例えばホーム画面に Python スクリプトのショートカットを置いて直接スクリプトを起動できれば,使い勝手的に普通の Android アプリと遜色ないのだが,残念ながらそれができない.いちいち Pydroid 開いてスクリプトをエディタで open して run しないといけない.うーん,ここだけがほんとに残念.

2020年4月29日水曜日

BIOS パスワードを,ぶっ壊す!

タイトルもやってる内容も 3周くらい周回遅れ.

某所であてがわれている PC は BIOS パスワードを入れないと起動しない.セキュリティ的には無意味なばかりか,自動的な Windows Update も阻害されてまさに百害あって一利無し.Windows9x 時代のセキュリティを未だに引きずってるとか情報セキュリティ部門はどこも無能ばかり.ということで,BIOS パスワードを,ぶっ壊す!
BIOS パスワードを解除するのは簡単だけどルール違反なので,それを技術的にどうにかしようというのがこの記事の趣旨.

Cobito Card というキー自動入力デバイスがあって,これがやりたいことそのものなんだけど,¥2,300 はやりたいことに対して高すぎ.ここで Arduino 使えばできるんじゃね? と思いつき,いろいろ調べてみると Atmega32U4 が載っているやつなら Human Interface Device (HID) になれるらしいので,AliExpress で¥330 で互換ボード get.

BIOS パスワードを,ぶっ壊す!

でサクッと,電源入ったらパスワード文字列を入力するプログラム書いてみた.

ここ見ながら作業開始から実際に動かすまでわずか 30分.Arduino 超お手軽.
ちなみにプログラム書き込みモードにするためにはリセットスイッチをダブルクリックすれば,6秒くらいだけ書き込みモードになるらしい.自分ははんだ付けがめんどくさかったのでピンセットでショートさせて対応したが,これで良ければはんだ付けすら不要.

で,やってみたら電源 OFF 状態からの BIOS パスワードは自動でやってくれたけど,再起動からの BIOS パスワードは入力されない.再起動時は Arduino の電源は入りっぱなしだから,当たり前っちゃ当たり前.これでは一番の目的である Windows Update 時の再起動時には効果がない.

BIOS パスワードを,ぶっ壊す!

なので作戦変更.この Arduino ボードは HID デバイスとして動作させたときも USB シリアルが生きているので,
(1) Arduino の電源が入ったら,無限に bios パスワードを入力する
(2) タスクスケジューラで Windows 起動時に (1) を止めるシリアルコマンドを Arduino に入力する
(3) グループポリシーで,Windows 終了時に (1) を再開するシリアルコマンドを Arduino に入力する
のようにやってみた.

シリアルに "ssss" が入力されたらパスワード入力停止,"gggg" が入力されたら再開する.

シリアルに入力するためには,以下のような powershell で入力できる.引数に ssss か gggg を指定する.これをタスクスケジューラ / グループポリシーに登録する.

これによって再起動でも無事 BIOS パスワードが自動入力されるようになった.もちろん Windows 起動後は入力はストップするので,ログイン画面で永遠 BIOS パスワードを入力するようなこともない.

最後にもう一度,BIOS パスワードを,

2019年3月3日日曜日

iEPG 絶滅

テレビ王国が iEPG サービスを終了してしまった.PC から録画予約するには iEPG 必須だったのに,「あんま流行ってないんでやめるわ」的にやめられて困る(;´д⊂)
昔はテレビ王国以外にもいつくかあった iEPG 番組表サイトもいつの間にかことごとく止めてるみたいで,探した限り iEPG 番組サイトはどこにもなかった.
さりとて,レスポンスがクソ遅い RD-S1004K の番組表から録画予約とか無理すぎるので,テレビ王国に iEPG を復活する Chrome 拡張を作って公開してみた

Chrome 拡張を初めて使ってみたけど,Web ページを好きなように書き換え放題なので,希望のリンクなんかを手軽に追加できる.
ただ今回はクリックしたら iepg ファイルを生成してダウンロードしないといけないのだけど,その方法はここに書いてあった.

これでもうしばらく戦えそうだヽ(´ー`)ノ

2019年2月9日土曜日

サクラエディタに改行をまたぐ検索・置換を実装する

●長いので結論だけ
サクラエディタに制限なしの「改行をまたぐ検索・置換」を実装してみた.
https://github.com/yoshinrt/SakuraVz

●技術的な話
サクラエディタの前は WZ Editor しか使ってなかったから (そして Wz では普通にできていたから) 知らなかったけど,多くのエディタでは改行をまたぐ検索・置換ができない,または行数に制限がある.

これは,大抵のエディタでは内部で行単位でデータ管理しており,次の行データと連結して検索しない限り例えば /\n\n+/ のようなパターンはマッチしない.じゃあらかじめ何行連結してから検索するの? というところで行数制限が発生し,例えば EmEditor では設定した行数以上にマッチする検索は出来ないし,サクラエディタでは 1行も連結しないので改行をまたぐ検索は一切できない.
自分は s/\n\n+/\n/g みたいな感じで空行を圧縮する置換をたまにするので,行数制限は不便.というわけで,行数制限がない改行をまたぐ検索・置換をサクラエディタに実装することにした.
(ちなみに最初から全部連結しとけば? というのは効率・処理速度の観点でやらない)

サクラエディタでこれをやるには,正規表現エンジン (RE エンジン) 側に,パターンにマッチする・しないという結果以外にもう一つ「部分的に一致した」を返す機能が必須になる.
例えば,検索パターン /\n\n+/ で検索対象文字列 "aaa\n" を検索してもマッチはしないが,パターンの途中 (\n の一個目) まではマッチしているので,「途中まではマッチした」という結果を RE エンジンが返す.呼び出し側はその結果を受けて,検索対象文字列に次の行を連結して再度検索を行うことを,完全にマッチ or マッチ失敗するまで繰り返すことで,行数制限がない検索をすることができる.

この機能を持っている RE エンジンは自分が探した限り PCRE2 (partial match) か Hyperscan (streaming mode) しか見つからなかった.今回はより使いやすそうな PCRE2 を使用することにした.bregonig (onigmo) の機能不足により,検索パターンをこねくり回したりしていた記述も PCRE2 のオプション一発で解決できるので,ソースコードもスッキリ出来て一石二鳥ヽ(´ー`)ノ

ただし,PCRE2 では partial match モードな置換は出来ないので,予め partial match モードで検索し必要な行数を連結した文字列に対して,置換を行う必要があった.

2019年1月12日土曜日

Intel の嫌がらせ

Intel 謹製の高速正規表現ライブラリであるところの hyperscan を使ってみようと思った.
ここ見ながら build してサンプル作って実行してみたら,

「ハンドルされない例外が 0x00007FF6BF7B5E4C (sample.exe) で発生しました: 0xC000001D: Illegal Instruction。」

オウフ.なかなか見ないエラーだな.

エラー起こしたアドレスの逆アセをみると「shlx」,これはどうやら BMI2 命令セット (AVX2 と同時に追加?) に含まれる命令っぽいのだが,うちの AMD A8 に載ってるわけがない.cmake が AVX2 の有無を認識してコンパイラオプション等をよきにはからってくれると思ってるんだけど,違うのだろうか? Intel CPU にしか hyperscan を使わせない嫌がらせか何か?

んーと思ったら,CMakeLists.txt で AVX2 を強制的に ON にしてるっぽい?
set(ARCH_C_FLAGS "/arch:AVX2")
set(ARCH_CXX_FLAGS "/arch:AVX2")
これをコメントアウトしたら,無事 AMD A8 でも動いたヽ(´ー`)ノ

2019年1月3日木曜日

ふゆやすみのこうさく

あけおめ.

超久々に車載データロガーを update.

自作データロガーのハードを 2号機にしてから,ラップタイマの磁気センサの感度が極端に悪くなって,ラップ計測できなくなってしまった.車からデータロガーのハードを外して調査・修理しようかと思ったが,
妥協発動

GPS ラップタイマ機能を自作データロガーの Android アプリに組み込んでしまうことにした.普通は GPS Laps とか使えば済むんだけど,自作データロガーの機能も無いと困るので (ここは妥協しないw).

Bluetooth 通信 (外部 GPS と通信) と,GPS ログからラップタイム算出するのは既に別のソフトで実装済みなのでサクッと移植.
問題はコントロールラインを設定する UI をどうしよう? というとこで,理想は Google マップなんかを表示させて GUI で設定することだけど,

妥協発動

一度サーキット毎に設定してしまえばそうそう変えるものではないし,凝った GUI は不要! というわけで,
←こういうのを Google マイマップ (PC) で作って kml にエクスポートして,

Android アプリでは
←こういうふうにその kml を選択できるようにしておいた.

磁気センサのラップタイマが動かなくなったのは残念だけど,GPS でも 3/100秒 くらいの精度が出るのはわかってるしね.サンデードライバーにはこれで十分っす.

ま,人生何事も妥協が大事ということで.

2018年12月8日土曜日

落ちクマ

PC から WiFi 経由で Android のファイルブラウズをしたいのだけれど,
・日本語ファイル名が化けない
・外部サーバを介さず LAN 内で完結する
・SD カードを読み書きできる
・上記の機能がすべて無料で使える
を満たす Android アプリが,何故か無い.

なので Cyanogenmod, LineageOS では内蔵の sshd を立ち上げていた (PC からは WinSCP) のだが,今のところこれが最強.
しかし Redmi Note 3 Pro を AOSP 系の Pixel Experience にしたら sshd が入っていなかった.
Android アプリにも sshd はあるけど,root じゃないので SD カードアクセスができず使えない.

仕方がないので dropbear を Android 向けに build することにした.
GitHub を漁るといろいろ Android に移植済みの dropbear があるが,最も新しそうな dropbear-android を使用することにする.

【手順】
(1) Android NDK 環境をここ見ながら構築する.
自分は↓で行けた.
/home/yoshi/android-ndk-r16b/build/tools/make-standalone-toolchain.sh --arch=arm --platform=android-21 --install-dir=/home/yoshi/android-toolchain
(2) dropbear-android のビルド
setenv TOOLCHAIN /home/yoshi/android-toolchain
./build-dropbear-android.sh
で,珍しく一発でビルドが通った.

で,RN3P に持っていって起動したら,
# /data/dropbear -r ./ssh/rsa_key_db -F -P ./ssh/pid -A -N root -T ./ssh/authorized_keys -U 0 -G 0
[23486] Dec 08 15:37:22 Not backgrounding
[23487] Dec 08 15:37:25 Child connection from 192.168.0.13:62545
[23487] Dec 08 15:37:27 Password auth succeeded for 'root' from 192.168.0.13:62545
[23487] Dec 08 15:37:27 Failed to open any /dev/pty?? devices
[23487] Dec 08 15:37:27 No pty was allocated, couldn't execute
[23487] Dec 08 15:37:27 Exit (root): Exited normally
んー,terminal の open に失敗してる? そもそも /dev/pty とか Android に無いんじゃないの?

調べてみると,Linux では openpty() で端末を open するのが一般的らしいが,Android に openpty() はない.しかし,ここで他の Android dropbear プロジェクトで,openpty() を独自実装しているものが見つかった.このコードをサクッとコピペして再ビルド.
[28075] Dec 08 21:54:33 Not backgrounding
[20372] Dec 08 22:03:01 Child connection from 192.168.0.13:55309
[20372] Dec 08 22:03:01 Password null
[20372] Dec 08 22:03:01 Password null
[20372] Dec 08 22:03:01 Password null
[20372] Dec 08 22:03:01 Pubkey auth succeeded for 'root' with key sha1!! ... from 192.168.0.13:55309
勝利ヽ(´ー`)ノ

上記のパッチ当て済みのものを GitHub に公開したんで,欲しい人はどうど.

2018年6月9日土曜日

VZ Editor 復活の狼煙

テキストエディタは使い慣れたものでないと著しくコーディング効率が落ちる.MS-DOS 時代は VZ Editor を使っていたので,Windows では自ずとのその後継の WZ Editor 4 (もう 16年前のバージョンw) を使っていたが,
・Unicode 対応がプア
・正規表現がバグっている
等々,限界が近くなってきた.普通に考えれば WZ の最新版を買えばいいのだろうけど,会社で個人購入のソフトを使っているのがバレるとめんどくさいは使えないのと,十数年前と違って今ではフリーのエディタも高機能なものがあるので,WZ の代替になるかいろいろ調べてみた.

●Emacs 系
Emacs lisp が強力なので,望みのことは多分できそう.ただし Windows で Emacs インストールはかなりめんどくさいようなのでパス.あと重い.

●Mery,サクラエディタ,秀丸 (は有料だけど)
一般的にはそこそこ強力なマクロ機能を持っているんだろうけど,自分的には機能が足りず,VZ の編集機能を実装することができなさそう.

●Notepad++
プラグインを自作すればかなりのことができそうな雰囲気なので,おそらく望みのことはできるんだろうけど,プラグイン開発のための情報が少なすぎた.プラグイン開発のための学習コストを考えると,順位は下げざるを得ない.

●xyzzy
マクロ機能は文句なしに強力.実はこれが本命ということでしばらく使ってみたのだけど,Emacs 系の独特の選択方法や,マウスを使った操作があまりにも他の Windows アプリとかけ離れているので,最終的に使うのを諦めた(;´д⊂)
あと開発が止まったようなので,もう更新されないエディタにわざわざ乗り換えるのもなぁ...

とフリーソフトは全滅か,と思ったところで,サクラエディタはソースコードが公開されていることを思い出した.これって考えようによっては究極のカスタマイズ機能だよなぁ... と思って,サクラエディタ VZ 化計画をおもむろに発動.というわけで,GitHub のサクラエディタをサクッと fork して公開中→https://github.com/yoshinrt/SakuraVz

2018年5月23日水曜日

SystemC で全信号の sc_trace() をなるべく楽にする方法(2)

以前「インスタンス階層ツリーを出してくれる機能はなさげ」と書いたけど,SystemC の全信号を階層付きでリストアップする方法はあることがわかった.
Why sc_object menber function trace() deprecated?
ただしリンク先にもあるように,一発で全信号を波形ダンプする方法があるわけではない.
# 信号名の一覧が取得できるだけ
しかし階層付きの信号一覧取得できれば,ほぼ目的は達成したと言って良い.というわけでコード.

最初に -DLIST_ALL_SIGNAL 付きでコンパイルして実行すると信号一覧が取得できる.それをスクリプトで適当に sc_trace() のコードに変換して trace_all_signal.h を生成する.あとは -DLIST_ALL_SIGNAL なしでコンパイル・実行すれば全信号のトレース付きで sim 実行される.
↓取得できる信号一覧
↑生成した trace_all_signal.h

前回の方法は,全モジュールに sc_trace() を埋め込むので記述が分散してそれなりに手間だが,今回の方法は 1箇所の記述で対応できるので楽といえば楽.

ただし,信号の配列の場合やメンバイニシャライザで信号名していない場合,取得した信号名はテンポラリな名前になってしまうため C++ 上の変数名と不一致を起こしコンパイルエラーになってしまう (上の例でいうと,sim_top0.signal_0 は存在せず,そのような変数名は trace_all_sighal.h から省かなければならない).

●各モジュールに sc_trace() 埋め込み
◎全信号をもれなくトレース可能
◎配列信号でも,正確な信号名を設定できる
×記述が分散する
×信号の増減は所詮手動で対応しなければならない

●全信号自動リストアップ
◎信号の増減に自動的に対応できる
◎1箇所にコードがまとまるのでメンテが楽
×2回コンパイルが必要
×name 設定していない (出来ない) 信号のトレース不可

楽さを取るか,もれなく信号をダンプするか.悩ましいところだなぁ.

2018年5月20日日曜日

ここがヘンだよ SystemC

SystemC は新規に設計された言語ではなく,C++ にライブラリを追加する形で実現されているため,いろいろと記述的にヘンであったり,煩雑なところがある.

(1) センシティビティリスト記述を,動作を記述している場所の近くに書けない (普通に書くと別ファイルになる)
(2) 信号を定義したら,その信号名を「文字列で」教えてやる必要がある.
(3) 前回の blog に書いた sc_trace() の問題.(2) と合わせると,信号の宣言,信号名の設定,トレースの設定,と同じような情報を 3箇所に書く必要がある.
(4) Verilog-2001 の always@(*) のようなセンシティビティリスト省略が出来ない
(5) Verilog-200x (いつの規格かわすれた) のインスタンス接続の省略表記「.*」が出来ない

こういうのって設計の頭使うところ以外で時間を食うことになるので,上記を改善するための SystemC preprocessor を作ってみた.

scpp.pl - SystemC preprocessor

我ながら SystemC のイライラポイントが大分改善されて満足ヽ(´ー`)ノ
下記の処理前後の diff を見てもられば,処理前の記述が大分削減されていることがわかってもらえると思う.

2018年5月11日金曜日

SystemC の sc_trace() をなるべく楽にする方法

SystemC で信号ダンプをするためには,自分でダンプしたい内部信号を階層含めて一個一個指定する必要があって超めんどくさい.一個一個,は他にも似たような記述があるので諦めるにしても,階層含めて,は根気良く書くのが無理なレベル.インスタンス階層ツリーを出してくれる機能とかあればいいんだけど,そういうのもなさげ.
どこのご家庭でもお困りですよね.
sc_trace( trace_f, hoge.fuga.signal_a, "hoge.fuga.signal_a" );
sc_trace( trace_f, hoge.piyo.signal_b, "hoge.piyo.signal_b" );

で,自分で試してみて,一番マシだと思った方法は,SC_CTOR() 内で sc_trace() すること.

this->name() で,インスタンス化されたときのこのモジュール名のフルパス名が取得できるので,sc_trace() の記述自体にはフルパスを記述する必要がなくなる.
この程度の記述であれば,ポート宣言のコピペ & 置換レベルで対応できる.
めんどくさいメンバイニシャライザでの信号名設定 (上記の★不要 の箇所) も不要.

なお trace_f は このモジュールがインスタンス化される前に sc_create_vcd_trace_file() しておく必要がある.

Cadence だとナントカ wizard でこの辺を自動化してくれるんだけど,パンピーには使えないしね...