2013年9月9日月曜日

疑似シリアル間を中継する

/dev/ptmxで作成した2つの疑似シリアル間を中継する。
スレーブをオープンするまでループバックしてしまうのが問題。


C言語
#define _XOPEN_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

static void dump(char *desc, void *data,int len)
{
	unsigned char *d = (unsigned char*)data;
	int i;
	printf("%s ",desc);
	for(i=0;i<len;i++)
	{
		printf("%02x",d[i]);
	}
	fputs("\n",stdout);
}

int main()
{
	unsigned char buf[64*1024];
	int fd1;
	int fd2;
	int m;
	int r;
	fd_set rdfs;
	
	
	fd1 = open("/dev/ptmx", O_RDWR | O_NOCTTY);
	if(fd1<0)
	{
		perror("open");
		return 1;
	}
	grantpt(fd1);
	unlockpt(fd1);
	printf("%s\n", ptsname(fd1));
	
	fd2 = open("/dev/ptmx", O_RDWR | O_NOCTTY);
	if(fd2<0)
	{
		perror("open");
		return 1;
	}
	grantpt(fd2);
	unlockpt(fd2);
	printf("%s\n", ptsname(fd2));
	
	
	while(1)
	{
		m = (fd1 > fd2) ? fd1 : fd2;
		
		FD_ZERO(&rdfs);
		FD_SET(fd1, &rdfs);
		FD_SET(fd2, &rdfs);
		
		r = select(m+1, &rdfs, NULL, NULL, NULL);
		
		if(r<0)
		{
			perror("select");
			return 1;
		}
		
		if(r)
		{
			if(FD_ISSET(fd1, &rdfs))
			{
				r = read(fd1, buf, sizeof(buf));
				if(r<0)
				{
					perror("read");
					return 1;
				}
				write(fd2, buf, r);
				dump(ptsname(fd1), buf, r);
			}
			
			if(FD_ISSET(fd2, &rdfs))
			{
				r = read(fd2, buf, sizeof(buf));
				if(r<0)
				{
					perror("read");
					return 1;
				}
				write(fd1, buf, r);
				dump(ptsname(fd2), buf, r);
			}
		}
	}
	
	return 0;
}
python
import os
import asyncore
import binascii


class SerialEmu(asyncore.file_dispatcher):

    def __init__(self):
        self.master, self.slave = os.openpty()
        self.slave_name = os.ttyname(self.slave)
        asyncore.file_dispatcher.__init__(self, self.master)

    def handle_read(self):
        d = os.read(self.master,2048)
        os.write(self.opposite.master,d)
        print 'RX %s %s' % (self.slave_name, binascii.b2a_hex(d))

    def writable(self):
        return False


s1 = SerialEmu()
s2 = SerialEmu()

print s1.slave_name
print s2.slave_name

s1.opposite = s2
s2.opposite = s1

asyncore.loop()

TCPとserialを中継する



> socat -T10 TCP-LISTEN:5555,fork,reuseaddr /dev/ttyS0,raw,b115200,echo=0

・TCPポート5555とシリアルを中継
・無通信10秒でTCP切断
・ボーレート115200
・ローカルエコーなし

2013年7月13日土曜日

pythonでTUN/TAPの中継する

TAPを2つ作ってその間を中継する。
以前はselectを使ってたけどasyncoreが便利。
29,30行目のoppositeに強引に送信関数を設定しているが、どうも美しくない。
どうすべきかなぁ

import fcntl
import struct
import asyncore

TUNSETIFF = 0x400454ca
IFF_TUN = 0x0001
IFF_TAP = 0x0002
IFF_NO_PI = 0x1000

class TunTap(asyncore.file_dispatcher):

    def __init__(self, ifname, flags):
        self.ifname = ifname
        self.fd = open('/dev/net/tun', 'r+b')
        ifr = struct.pack('16sH', ifname, flags)
        res = fcntl.ioctl(self.fd, TUNSETIFF, ifr)
        self.ifname = struct.unpack("16sH", res)[0].strip('\x00')
        asyncore.file_dispatcher.__init__(self, self.fd)

    def handle_read(self):
        self.opposite.send(self.recv(2048))

    def writable(self):
        return False

t1 = TunTap( 'tap1', IFF_TAP | IFF_NO_PI )
t2 = TunTap( 'tap2', IFF_TAP | IFF_NO_PI )

t1.opposite = t2
t2.opposite = t1

asyncore.loop()

2013年5月18日土曜日

u-bootからkernelにパラメータの渡し方


いろんなやり方があるようだが、今使っているam335x用のarmの場合。
かつ、u-bootのコンパイル時に以下を定義した場合。

#define CONFIG_CMDLINE_TAG
#define CONFIG_SETUP_MEMORY_TAGS
#define CONFIG_INITRD_TAG



参考
http://www.simtec.co.uk/products/SWLINUX/files/booting_article.html

パラメータの種類ごとにTAGがある。一覧


u-bootのbootmコマンドでinitramfsを指定した場合、ATAG_INITRD2タグ(値0x54420005)を使ってイメージのアドレスとサイズをkernelに渡す。

カーネルコマンドラインのbootargsも同様に、ATAG_CM_LINEタグ(値0x54410009)を使う。


これらの情報は物理メモリの開始アドレス+0x100に置かれるのが一般的のよう。
board/ti/am335x/board.cのboard_init()内で
gd->bd->bi_boot_params = PHYS_DRAM_1 + 0x100;
とあるのがそれ。


ただし、R2レジスタに入れるのが筋のようだ。
arch/arm/lib/bootm.cのboot_jump_linux()内で
r2 = gd->bd->bi_boot_params;
とある。


ATAGを使う以外にFDT(Flat Device Tree)を使うパターンもあるみたいだが
※Device Tree Blob (dtb)?
こちらの方がパラメータの種類も豊富みたいだがフォーマットがいまいちわからない

参照
https://export.writer.zoho.com/public/rreginelli/Working-with-Device-Trees1/fullpage

u-bootからLinux+initramfsの起動

前回書いたようにinitramfsイメージを作成し、さらにu-boot用イメージにすると便利だと気づいたメモ。

initramfsイメージの作成

> gen_initramfs_list.sh -u squash -g squash rootfsdir > list
> gen_init_cpio list | gzip > rootfs.cpio.gz

u-bootイメージの作成
> mkimage -A arm -O linux -T ramdisk -C none -a 0x82000000 -n "Linux userland" -d rootfs.cpio.gz rootfs.cpio.gz.ub


ここで作成したrootfs.cpio.gz.ubをSPIフラッシュに書き込んどいて、u-bootで読み出す例。

#SPIフラッシュの準備
> sf probe 0
#SPIフラッシュのoffset=0x400000,length=0x400000のkernelイメージをメモリ0x88000000番地に
> sf read 0x88000000 0x400000 0x400000
#SPIフラッシュのoffset=0x800000,length=0x400000のrootfs.cpio.gz.ubをメモリ0x89000000番地に
> sf read 0x89000000 0x800000 0x400000
#上で読み込んだu-bootイメージをそれぞれ展開してkernelを起動する
> bootm 0x88000000 0x89000000


bootmコマンドに2つ目の引数があるとは知らなかった。

initramfsについては、mkimageで作成時「-a 0x82000000」と指定しているので、bootmは0x89000000のイメージを0x82000000に展開する。

以前のやりかたではbootargsに「initrd=0x83000000,0x3c112233」のように指定しなければならなかったが、bootmを使えばパラメータは自動的にkernelに渡してくれる。


2013年5月16日木曜日

initramfsイメージ内のUIDを変える

initramfsイメージを作成する例えとして、こことかでは次のようなコマンド例が紹介されている。
> (cd rootfsdir; find . | cpio -o -H newc | gzip) > rootfs.cpio.gz

しかし、これではファイルの所有者情報(UID,GID)がそのまま残ってしまう。
所有者をroot(UID=0,GID=0)に変更したいが、cpioコマンドでそれを行う方法がわからない。

もちろん作業環境でroot権限があればchownしてからcpio+gzipすることもできるが、
root権限のない環境ではそうもいかない。

mkfs.jffs2にある--squashオプションみたいなのがあればと探してみた。


kernelソースにinitramfsを含めることができる=そのためのツールがあるのね。
使うのはkernelソース内にあるscripts/gen_initramfs_list.shとusr/gen_init_cpio.c

事前準備でusr/gen_init_cpio.cをコンパイルしておく。
> gcc gen_init_cpio.c -o gen_init_cpio


イメージ作成
> gen_initramfs_list.sh -u squash -g squash rootfsdir > list
> gen_init_cpio list | gzip > rootfs.cpio.gz

gen_initramfs_list.shの-u,-gオプションを指定してやるとlistファイルの中のUID,GIDを0で吐き出してくれる。
あとはgen_init_cpioにlistを渡して固めればok

2013年5月10日金曜日

linuxでGPIOの状態変化を知りたい

LinuxでGPIOの状態が変わったことを割り込み的にreadしたい場合の話・・・

最初に触ったのがarmadillo-420で、ここにもあるようにpoll()を使った場合はPOLLIN、select()を使った場合はreadfdsでファイルディスクリプタを指定する。

ところが、am3352の載った別ボードを触った時、上記のソースでは動かない。
なんでだなんでだと調べてるとここに書いてあった。
pollの時はPOLLPRIとPOLLERR、select()の場合はexceptfdsで指定するんだと。

一般的にどうかわからないけど、linuxのドキュメントはam3352のパターンと同じなので、armadilloが異端なのかな?