俺言語。

自分にしか理解できない言語で書かれた備忘録

【Android, Java】Mapのstaticな宣言

Pythonのdictの様な連想配列を定数クラス内で定義しておきたいと思ったときに使用.
通常mapはmapを宣言した後,addで一つずつキーとデータを追加していくが,定数として使用したいのでコンストラクタ内でのaddは出来ない.(定数クラスなので使用先でインスタンス化しない)

そのためにスタティックイニシャライザというものを使用.

定数クラスは下記のようにstaticとアスタリスクでインポートすると使用可能.

import static com.example.******.ConstConfig.*;

こちらを参考にさせて頂きました.
neos21.net

【Android】複数行のテキストボックスの最終行を表示

自作のコンソール画面を作っている際に,

  • 複数行の文字表示
  • 文字列が追加されたら最後の行を自動表示
  • 文字表示が変わらないときは自由にスクロールアップして過去の文字が見れるように

という機能を実装.

ポイントは

  • スクロールさせたいTextViewをScrollView内に記載 (レイアウト内,xml) → これでテキストボックスがスクロール可能に.
  • 文字列を追加した時に,scrollview.smoothScrollTo(0, textView_Console.getBottom());を呼び出す.

これだけで,文字が追加されると一番下まで自動的にスクロールされる.

こちらを参考にさせて頂きました.
stackoverflow.com

【Android, Spinner】Spinnerの文字色を動的に変化させる方法

スピナーで選択した文字が条件に一致したときに通常の白から緑に変化させて,選択した文字のstatusを明示できるようにしたもの.

流れは,

  1. SpinnerにセットするArrayAdapterを自作する.
  2. 自作ArrayAdapterにテキストカラーを保持するメンバを追加
  3. getView()の中でTextViewの文字色をメンバの色で更新し,そのTextViewを戻り値にする
  4. 自作メソッドを追加し,テキストカラーを外部から変更できるようにする.
  5. テキストカラーを操作したとはアダプタークラスに変更通知(customAdapter.notifyDataSetChanged();)を送り,画面を更新する

ポイントは,

  • 表示される色だけを操作する場合はgetView()の内部を変更する.プルダウンで表示されるリストの色はgetDropDownView()の方でやれるはず.
  • DropDownリストを変えなくてもoverrideする必要あり.その際に,LayoutInflater.from(getContext()).inflate(R.layout._spinner_item, parent, false); としてあげないとプルダウンでタップできるエリアが狭くなってしまい,選択しづらくなる.
  • getDropDownView()内で,表示するテキストとテキストカラーも明示が必要.
/***
* スピナーの文字色を動的に返るための自作ArrayAdapterクラス
*/
public class CustomAdapter extends ArrayAdapter<String>{

    int textcolor = Color.WHITE;
    String textString =  new String(" ");

    // Constructor
    public CustomAdapter( Context context, int resource, String[] strings){
    super(context, resource, strings);
    }

    @NonNull
    @Override
    // スピナーに表示されるビューのみ色を変えられる様に変更する
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        TextView textView
                    = (TextView)((LayoutInflater.from(getContext()).inflate(
                    R.layout._spinner_item, parent, false)));

        textString = super.getItem(position); // Spinnerを選択したときのテキストの変更も外でやる必要あり
        textView.setText(textString);

        // スピナーに表示されるテキストの色変更
        textView.setTextColor(textcolor);

        return textView;
    }

    @Override
    // DropDownViewはスピナーを押したときに表示されるもの.これはそのままいじらない
    public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        TextView textView
                = (TextView)((LayoutInflater.from(getContext()).inflate(
                R.layout._spinner_dropdown, parent, false)));

        textView.setText(super.getItem(position)); // そのままいじらなくてもこれは明示しておく必要がある
        textView.setTextColor(Color.BLACK); // そのままいじらなくてもこれは明示しておく必要がある

        return textView;
    }

    //** Spinnerに表示されるTextViewの色を操作する **//
    public void setCustomTextViewColor( int newColor ) {
        textcolor = newColor;
    }
}

こちらを参考にさせて頂きました.
www.synapse.ne.jp
android-note.open-memo.net
qiita.com

【C,ポインタ】改めてCのポインタ 個人的まとめ

あっているかわからないけど,ポインタは結局は組み込みなどメモリ容量が制限される環境と,戻り値が2以上の関数でグローバル関数を使いたくない場合に有効な手段.
裏を返すと,メモリに余裕があって,動けば良くて,ポインタで躓いて時間を食うくらいなら,ポインタ関連を避けて通ったほうがいいのではと思う(現時点での理解).

とは言えもう一度整理.

混乱するポイントは,変数をポインタで宣言した後は*(アスタリスク)なしでアドレスを示す変数になる.という点.この図は大変分かりやすい.

も一つ混乱する原因となる,変数の配列の配列名だけの場合はその配列の先頭のアドレスを表す,という点.

uint8_t data[2] = {0, 1};

data = &data[0]; // <-これは同じ意味になる

これは実際良く使われていて,関数に配列を渡す場合,データが大きくなってしまうので配列の変数を渡すパターンで

uint8_t data[2] = {0, 1};
func(data);

func(uint8_t *recv_data){
    Serial.println(*recv_data) // 引数はポインタで宣言されているのでデータへのアクセスは*(アスタリスク)が必要.
}

みたいなケース.
注意点は関数の宣言側ではアドレスが来るのでポインタで引数を宣言しておくこと.

この辺りの例外的なルールがCのポインタ回りをわかりづらくしている要因のひとつかと.なんでこんなルールにしたのか理由があれば調べてみたい.

こちらを参考にさせていただきました.
www.sgnet.co.jp
www9.plala.or.jp
9cguide.appspot.com

【C】2byte以上のデータを1byteずつ送信する方法

例えば65535(0xFFFF)のような2byteのデータをシリアル通信で送信する場合、

1) 文字列のまま送る→ 0x54 0x53 0x53 0x51 0x53 で5byte必要
2) バイナリデータで送信 → 0xFF 0xFF で2byte

とバイナリデータで送信する方が効率がよい.

2byteデータをバイナリデータで送信する場合は上位byteと下位byteに分けて送信する必要があるため,ビットシフトなどを使って

uint8_t b[2];
b[0] = 65535 >> 8
b[1] = 65535 - (b[0]<<8) // そのまま65535を代入しても上位8bit分は自動的に削られるかも

// ビットシフトは加減算より優先順位が低いのでカッコが必要(知らんかった…)

とする必要があるが,これをCの共用体と構造体を使うともう少し簡単にできる.
たとえばCAN ID(2byte)とデータ1byteを送信する場合は,

union myuni
{
    struct{
        uint16_t id;
        uint8_t sig;
    };
    uint8_t bin[sizeof(uint8_t) * (2+1)];
};

と,共用体の中に構造体を定義して,

myuni.id = 65535;
myuni.sig = 255;
Serial.write(myuni.bin, 3);

とするとCAN IDの2byteを上位byteと下位byteに自動的に分割してくれるのでそのまま送信できる.

ポイントは,共用体は複数のメンバがメモリを共用していて,共用体のサイズは最もサイズの大きなメンバに合わせる点.
これによって,構造体の中のメンバのメモリ位置(今回の例ではidとsig)と共用体のメンバ(bin)のメモリ位置が一致するので,binにアクセスすると,idとsigに代入した値が入っている.

こちらを参考にさせて頂きました。
hawksnowlog.blogspot.com

【Arduino】シリアル通信の送受信バッファサイズ変更

Arduino Micoroのシリアル送受信バッファサイズ、初期設定は64byteらしい(RAMサイズによっては16byte).

SPIで受信したCANデータをシリアルで送信する際に,IDあたり12byte(ID 2byte, data 8byte, start/end時にend符号で各1byte)に加えて, SLIPフォーマットはデータによりデータ長が2倍まで長くなることを考慮すると最大22byte送信することになる.
これに対して送信バッファ64byteでは複数IDのデータを立て続けに送信する場合,バッファが溢れないか若干不安なので今回は128byteに変更.

変更はC:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino\HardwareSerial.hの
赤枠部分.MicroのRAMサイズは1023より大きい(ネットでは2559との記事ありhttps://github.com/arduino/Arduino/issues/3822)ようなので,そちらの数値を変更する.

こちらを参考にさせて頂きました。
blog.revetronique.com

【CANUSB】CANUSBをwindows11で使用

LAWICEL製のCANUSBデバイスをWindows11で使用するまでの覚え書き
ドライバのインストールと、CANUSBをWindows11で認識できるようにするための2ステップが必要

ドライバのインストール
  1. Windowsをテストモードに設定するために、BIOSからSecure bootをdisableにする
  2. 管理者権限のコマンドプロンプトで下記を入力、再起動するとデスクトップ右下にテストモードの表示がでる。
bcdedit /set TESTSIGNING ON
  1. CANUSBをPCに接続
  2. FTDIのドライバをインストール
  3. テストモードの解除
bcdedit -set TESTSIGNING OFF
CANUSBのProduct ID変更
  1. Windows7までのPCにFT ProgをインストールしてCANUSBを接続
  2. Product IDを6001に変更
  3. Windows11にCANUSBを接続して、デバイスマネージャから USBSerialなんとか と表示されているデバイスを探して、プロパティから”VCPをロードする”を選択
  4. CANUSBの抜き差しかPC再起動

algorithm.joho.info