e-tipsmemo

ごった煮

C# sscanf の代替

C#でsscanfしたいなという人が絶対にいると思っていたら
ネットにあったのでその紹介。

www.blackbeltcoder.com

これは同時に以下のTextParserというものを利用している。
(Microsoft.VisualBasic.FileIOにもTextParserクラスがあるが、それとは別)
www.blackbeltcoder.com

private void button1_Click(object sender, EventArgs e)
{
    ScanFormatted scan = new ScanFormatted();

    scan.Parse("hoge1foo2bar3", "hoge%dfoo%dbar%d");

    foreach (var item in scan.Results)
    {
        Debug.WriteLine("{0}", item);
    }

//1
//2
//3
}

のようだ。

C# serialport ReadExisting

急に作りたくなったもののためのデバッグのために
UARTでパソコンに情報を送信しているが
それを可視化したほうが分かりやすかったので寄り道。

フォームアプリケーションが
楽なのでC#を使用。
2.0あたりで適当に使ってから久しぶりに使ったきがする。

\r\nで通信を区切っているがReadLineだとエラーが出るので
ReadExistingを使う。


COMポートの列挙(comboBoxで選べるように)

private void Form1_Load(object sender, EventArgs e)
{
    string[] ports = SerialPort.GetPortNames();

    foreach (var item in ports)
    {
        comboBox1.Items.Add(item);
    }

    comboBox1.SelectedIndex = 1;
}

データの受信インベント
区切り文字(delim=\r\n or \n)があるときは必ず(?)末尾っぽいので
出力してバッファーを空にする。

private string buffer;

private void DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    if (serialPort1.IsOpen == false)
    {
        return;
    }

    try {
        buffer += serialPort1.ReadExisting();
                
        if (buffer.IndexOf(delim) >= 0)
        {
            Debug.WriteLine(buffer);
            buffer = string.Empty;
            Debug.WriteLine("---------------");
        }
    }
    catch (Exception ex) {
        MessageBox.Show(ex.Message);
    }

    if (buffer.Length > 1024)
    {
        buffer = string.Empty;
    }
}

区切り文字なくてもバッファーが長くなると困るので適当にリフレッシュ。
(ココらへんは適当仕様)

あとは受信できた一行なんとかする。

BD6231F-E2動作テスト

急に作りたくなったものがあるので
秋月電子の良さそうなモータードライバ
akizukidenshi.com
の動作テスト
雑な図
f:id:katakanan:20170625205945p:plain
モータードライバー自体の電源は6Vでも
入力電圧Hレベルは2.0VなのでmbedのPWM(3.3V)でもOK。

ついでに可変抵抗でも繋いで、
AD変換した値を読み取り、
速度が変わっていることを確認する。

#include "mbed.h"

DigitalOut myled(LED1);
AnalogIn ain(p20);

PwmOut fin(p22);
PwmOut rin(p21);

int main() {
    
    fin.period(0.000010);
    rin.period(0.000010);

    rin = 0;

    while(1) {
        fin = ain;
    }
}

モーターにエンコーダーとかついていたら面白かったが
mbedにはそれをカウントするために周辺回路がない

Bash on Windowsをイイカンジにする② (fish shellのインストール)

前回の続き
e-tipsmemo.hatenablog.com

右クリックでアイコンを表示

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\Directory\Background\shell\bash]
"icon"="%USERPROFILE%\\AppData\\Local\\lxss\\bash.ico"

ターミナルエミュレーターとして
github.com

ついでにfishをインストールして

sudo apt-add-repository ppa:fish-shell/release-2
sudo apt update
sudo apt install fish

wsl-terminalのetc/wsl-terminal.confで
shell=fishにしてしまった。

RN-42動作確認

急に作りたくなったものがあるので
それのためにRN-42の動作テストを行った。
mbed
RN-42
f:id:katakanan:20170624193501p:plain

#include "mbed.h"

Serial rn42(p13,p14);
Serial pc(USBTX, USBRX);
DigitalOut myled1(LED1);
DigitalOut myled2(LED2);
DigitalOut myled3(LED3);
DigitalOut myled4(LED4);
int main() {
 
    rn42.baud(115200);
    pc.baud(115200);
    wait(1);
    
    while (1) {
        myled1 = !myled1;
        wait(0.1);
        if (pc.readable())
        {
            myled2 = !myled2;
            rn42.putc(pc.getc());
        }
        
        if (rn42.readable())
        {
            myled3 = !myled3;
            pc.putc(rn42.getc());
        }
    }
}

RN-42モジュールのCTSをGNDに落としておく。
www.microchip.com

kernel moduleの個人的なテンプレート

キャラクタデバイスドライバのkernel moduleの個人的なテンプレート
kernelは4あたり

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <asm/uaccess.h>

#define DEVNAME "hello"

#define MINOR_COUNT 1

MODULE_LICENSE("Dual BSD/GPL");

struct hello_dev
{
	int major;
	int minor;
	dev_t dev_id;
	struct cdev *pcdev;
	struct class* pclass;
	struct device* pdevice;
};

static struct hello_dev *pdev;

static int hello_open(struct inode *inode, struct file* flip)
{
	pr_info("dev open\n");
	return 0;
}

static int hello_release(struct inode *inode, struct file* flip)
{
	pr_info("dev close\n");
	return 0;
}

static ssize_t hello_read(struct file *flip, char __user *buf, size_t count, loff_t *offset)
{
	pr_info("dev read\n");
	return 0;
}

static ssize_t hello_write(struct file *flip, const char __user *buf, size_t count, loff_t *offset)
{
	pr_info("dev write\n");
	return 0;
}

static long hello_ioctl(struct file *flip, unsigned int cmd, unsigned long arg)
{
	pr_info("dev ioctl\n");
	return 0;
}

static struct file_operations hello_fops =
{
	.owner = THIS_MODULE,
	.open = hello_open,
	.release = hello_release,
	.read = hello_read,
	.write = hello_write,
	.unlocked_ioctl = hello_ioctl,
};

static int hello_init(void)
{
	int ret = -ENOMEM;

	pr_info("hello\n");

	pdev = kmalloc(sizeof(struct hello_dev), GFP_KERNEL);

	if(pdev == NULL)
	{
		pr_err("cannot alloc kern mem\n");
		return -ENOMEM;
	}

	pdev->pcdev = kmalloc(sizeof(struct cdev), GFP_KERNEL);

	if(pdev->pcdev == NULL)
	{
		pr_err("cannot alloc kern mem for cdev\n");
		goto pdev_free;
	}

	ret = alloc_chrdev_region(&(pdev->dev_id),
					0,
					MINOR_COUNT,
					DEVNAME);

	if(ret < 0)
	{
		pr_err("cannot alloc chrdev region\n");
		goto cdev_free;
	}

	cdev_init(pdev->pcdev, &hello_fops);

	pdev->pcdev->owner = THIS_MODULE;
	
	ret = cdev_add(pdev->pcdev, pdev->dev_id, MINOR_COUNT);

	if(ret < 0)
	{
		pr_err("fail to add cdev\n");
		goto cdev_unregist;
	}

	pr_info("mojor:%d\n", MAJOR(pdev->dev_id));
	pr_info("minor:%d\n", MINOR(pdev->dev_id));

	pdev->pclass = class_create(THIS_MODULE, DEVNAME);

	if(IS_ERR(pdev->pclass))
	{
		pr_err("fail to create class\n");
		ret = PTR_ERR(pdev->pclass);
		goto cdev_del;
	}

	pdev->pdevice = device_create(pdev->pclass, NULL,
						pdev->dev_id,
						NULL,
						DEVNAME);

	if(IS_ERR(pdev->pdevice))
	{
		pr_err("fail to create device\n");
		ret = PTR_ERR(pdev->pdevice);
		goto class_destroy;
	}

	pr_info("create success\n");
	return 0;

class_destroy:
	class_destroy(pdev->pclass);

cdev_del:
	cdev_del(pdev->pcdev);

cdev_unregist:
	unregister_chrdev_region(pdev->dev_id, MINOR_COUNT);

cdev_free:
	kfree(pdev->pcdev);

pdev_free:
	kfree(pdev);

	return ret;
}

static void hello_exit(void)
{
	device_destroy(pdev->pclass, pdev->dev_id);
	class_destroy(pdev->pclass);
	cdev_del(pdev->pcdev);
	unregister_chrdev_region(pdev->dev_id, MINOR_COUNT);
	kfree(pdev->pcdev);
	kfree(pdev);
	pr_info("Goodbye...\n");
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_DESCRIPTION("kernel module template");

stackoverflow.com

書き方を調べていたところ
cdevを登録するのに2つの方法があるらしい。

int register_chrdev(unsigned int major, const char *name,
    struct file_operations *fops);

struct cdev my_cdev ;
...
cdev_init(&my_cdev,&my_fops);
cdev_add(&my_cdev,num, count)

という方法らしいが、前者はcdevを意識する必要がない。

stackoverflow.com
これは前者でいいじゃんみたいな感じ。。

しかしここで(ちょっと古い)
The cdev interface [LWN.net]
cdev_addが行われるとすぐにkernelによってファイルオペレーションを呼ぶことが可能なので、
呼関連付けられているデバイスの完全な初期化が終わるまではcdev_addを呼ぶべきではない。

と書かれている。

これを踏まえるとデバイスがちゃんと見つかって、probe関数が呼ばれたときに、デバイスを初期化して、
最後にcdev_addするのが良いのだろうか・・・

Bash on Windowsをイイカンジにする

右クリックでBash起動
Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\Directory\Background\shell\bash\command]
@="C:\\Windows\\System32\\bash.exe"


少し前のアップデートによって、Bash On Windowsから
Windowsのアプリケーション(.exe)が起動できるようになった。
ので

Bashからexplorerでその場を開く。

.bashrcや.zshrcなどに

alias explorer="explorer.exe \".\""
適当なアプリで開く
alias hoge="cmd.exe /c \"start $1\""

Bashからデフォルトのアプリで開く。
Macのopenコマンドのようなもの。
(Linuxには別の目的のopenコマンドがすでにある。
何かよいエイリアス名にしたい。)