-1ボタンを表示させてみた

この前の高専カンファで少し話が出たから作ってみた。
Chromeのエクステンションとして組み込むと、Google+のストリームに-1ボタンが現れるよ!
http://sora-blue.net/~shogo82148/minus-one.crx


ってところまでは簡単にできた。
押しても何も起きません。

押されたよ!って情報をどこに保存するかが問題なんだよね。
Google+ APIは現段階では読み込み専用だし、その他の保存場所を確保するのは面倒。
何かアイデアプリーズ!

関数を呼び出すとなぜかリセットがかかる件について

AVRのプログラムで関数呼び出しすると、なぜかマイコンリセットがかかる現象に悩まされています。

わけがわからないので、以下の簡単なLEDチカチカプログラムでテスト。

  • Osで最適化、ターゲットはATMEL AVR ATMega64です。PC3にLEDのアノードが接続されています。

うまく動けば、0.5秒点灯、5秒点灯を繰り返すはず。

#include <avr/io.h>
#include <util/delay.h>

#define PIN_LED_GREEN	PC3
#define PIN_LED_RED		PC2
#define PIN_LED_POWER	PC5

static void initialize(void);

void FlushLED(uint8_t flag) {
	PORTC |= _BV(PIN_LED_GREEN);
	if(flag) {
		_delay_ms(500);
	} else {
		_delay_ms(5000);
	}
	PORTC &= ~_BV(PIN_LED_GREEN);
	_delay_ms(500);
}

int main(void) {
	initialize();
	for(;;) {
		FlushLED(1);
		FlushLED(0);
	}
	return 0;
}


static void initialize(void)
{
	//PORTC
	//LEDと電源制御用のピンを出力設定
	//その他のピンはプルアップ入力
	DDRC = _BV(PIN_LED_GREEN) | _BV(PIN_LED_RED) | _BV(PIN_LED_POWER);
	PORTC = ~(_BV(PIN_LED_GREEN) | _BV(PIN_LED_RED) | _BV(PIN_LED_POWER));
}

結果:

LEDが約0.5秒ごとに点滅を繰り返す。

一応アセンブラ出力も載せておきます。誰か助けてください><


main.elf: file format elf32-avr

Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000100 00000000 00000000 00000054 2**1
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .debug_aranges 00000020 00000000 00000000 00000154 2**0
CONTENTS, READONLY, DEBUGGING
2 .debug_pubnames 00000028 00000000 00000000 00000174 2**0
CONTENTS, READONLY, DEBUGGING
3 .debug_info 000001fe 00000000 00000000 0000019c 2**0
CONTENTS, READONLY, DEBUGGING
4 .debug_abbrev 0000011d 00000000 00000000 0000039a 2**0
CONTENTS, READONLY, DEBUGGING
5 .debug_line 0000018b 00000000 00000000 000004b7 2**0
CONTENTS, READONLY, DEBUGGING
6 .debug_frame 00000030 00000000 00000000 00000644 2**2
CONTENTS, READONLY, DEBUGGING
7 .debug_str 00000110 00000000 00000000 00000674 2**0
CONTENTS, READONLY, DEBUGGING
8 .debug_loc 0000009e 00000000 00000000 00000784 2**0
CONTENTS, READONLY, DEBUGGING

Disassembly of section .text:

00000000 <__vectors>:
0: 0c 94 46 00 jmp 0x8c ; 0x8c <__ctors_end>
4: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
8: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
c: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
10: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
14: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
18: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
1c: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
20: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
24: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
28: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
2c: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
30: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
34: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
38: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
3c: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
40: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
44: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
48: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
4c: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
50: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
54: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
58: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
5c: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
60: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
64: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
68: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
6c: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
70: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
74: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
78: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
7c: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
80: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
84: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
88: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>

0000008c <__ctors_end>:
8c: 11 24 eor r1, r1
8e: 1f be out 0x3f, r1 ; 63
90: cf ef ldi r28, 0xFF ; 255
92: d0 e1 ldi r29, 0x10 ; 16
94: de bf out 0x3e, r29 ; 62
96: cd bf out 0x3d, r28 ; 61
98: 0e 94 73 00 call 0xe6 ; 0xe6


9c: 0c 94 7e 00 jmp 0xfc ; 0xfc <_exit>

000000a0 <__bad_interrupt>:
a0: 0c 94 00 00 jmp 0 ; 0x0 <__vectors>

000000a4 :
#define PIN_LED_POWER PC5

static void initialize(void);

void FlushLED(uint8_t flag) {
PORTC |= _BV(PIN_LED_GREEN);
a4: ab 9a sbi 0x15, 3 ; 21
if(flag) {
a6: 88 23 and r24, r24
a8: 51 f0 breq .+20 ; 0xbe
aa: 88 e8 ldi r24, 0x88 ; 136
ac: 93 e1 ldi r25, 0x13 ; 19
milliseconds can be achieved.
*/
void
_delay_loop_2(uint16_t __count)
{
__asm__ volatile (
ae: 28 ec ldi r18, 0xC8 ; 200
b0: 30 e0 ldi r19, 0x00 ; 0
b2: f9 01 movw r30, r18
b4: 31 97 sbiw r30, 0x01 ; 1
b6: f1 f7 brne .-4 ; 0xb4
__ticks = (uint16_t) (__ms * 10.0);
while(__ticks)
{
// wait 1/10 ms
_delay_loop_2(((F_CPU) / 4e3) / 10);
__ticks --;
b8: 01 97 sbiw r24, 0x01 ; 1
__ticks = 1;
else if (__tmp > 65535)
{
// __ticks = requested delay in 1/10 ms
__ticks = (uint16_t) (__ms * 10.0);
while(__ticks)
ba: d9 f7 brne .-10 ; 0xb2
bc: 09 c0 rjmp .+18 ; 0xd0
be: 80 e5 ldi r24, 0x50 ; 80
c0: 93 ec ldi r25, 0xC3 ; 195
c2: 28 ec ldi r18, 0xC8 ; 200
c4: 30 e0 ldi r19, 0x00 ; 0
c6: f9 01 movw r30, r18
c8: 31 97 sbiw r30, 0x01 ; 1
ca: f1 f7 brne .-4 ; 0xc8
{
// wait 1/10 ms
_delay_loop_2(((F_CPU) / 4e3) / 10);
__ticks --;
cc: 01 97 sbiw r24, 0x01 ; 1
__ticks = 1;
else if (__tmp > 65535)
{
// __ticks = requested delay in 1/10 ms
__ticks = (uint16_t) (__ms * 10.0);
while(__ticks)
ce: d9 f7 brne .-10 ; 0xc6
_delay_ms(500);
} else {
_delay_ms(5000);
}
PORTC &= ~_BV(PIN_LED_GREEN);
d0: ab 98 cbi 0x15, 3 ; 21
d2: 88 e8 ldi r24, 0x88 ; 136
d4: 93 e1 ldi r25, 0x13 ; 19
d6: 28 ec ldi r18, 0xC8 ; 200
d8: 30 e0 ldi r19, 0x00 ; 0
da: f9 01 movw r30, r18
dc: 31 97 sbiw r30, 0x01 ; 1
de: f1 f7 brne .-4 ; 0xdc
{
// wait 1/10 ms
_delay_loop_2(((F_CPU) / 4e3) / 10);
__ticks --;
e0: 01 97 sbiw r24, 0x01 ; 1
__ticks = 1;
else if (__tmp > 65535)
{
// __ticks = requested delay in 1/10 ms
__ticks = (uint16_t) (__ms * 10.0);
while(__ticks)
e2: d9 f7 brne .-10 ; 0xda
_delay_ms(500);
}
e4: 08 95 ret

000000e6

:
static void initialize(void)
{
//PORTC
//LEDと電源制御用のピンを出力設定
//その他のピンはプルアップ入力
DDRC = _BV(PIN_LED_GREEN) | _BV(PIN_LED_RED) | _BV(PIN_LED_POWER);
e6: 8c e2 ldi r24, 0x2C ; 44
e8: 84 bb out 0x14, r24 ; 20
PORTC = ~(_BV(PIN_LED_GREEN) | _BV(PIN_LED_RED) | _BV(PIN_LED_POWER));
ea: 83 ed ldi r24, 0xD3 ; 211
ec: 85 bb out 0x15, r24 ; 21
}

int main(void) {
initialize();
for(;;) {
FlushLED(1);
ee: 81 e0 ldi r24, 0x01 ; 1
f0: 0e 94 52 00 call 0xa4 ; 0xa4
FlushLED(0);
f4: 80 e0 ldi r24, 0x00 ; 0
f6: 0e 94 52 00 call 0xa4 ; 0xa4
fa: f9 cf rjmp .-14 ; 0xee

000000fc <_exit>:
fc: f8 94 cli

000000fe <__stop_program>:
fe: ff cf rjmp .-2 ; 0xfe <__stop_program>


追記

解決しました。結論からいうとATMega103互換動作で動いてました。互換動作中は拡張I/O空間がなくなる分、少しメモリ空間が小さくなります。それによってスタックが割り当てられてたアドレスにはメモリが割り当てられず、関数呼び出しのようなスタックにアクセスする動作をすると落ちてしまったというわけです。

と、いうところまではいいんだけど、なぜ!なぜ!デフォルトの動作がATMega103互換動作なんだああああ!!!!


結論。ATMega64を使うときは、拡張ヒューズビットのM103Cのビットを1(プログラム)にしてから使いましょう。

Visual Studio 2010 Express のプロパティページでユーザマクロを使う

Visual Studio のプロパティページでは、外部ヘッダーファイルやライブラリへのパスをGUIで設定する必要がことができる。

SDLやらOpenCVやらを使いたくなったので、ここをいじってたわけだけど、ヘッダーファイルには「C:\SDL\include」を追加して・・・リンク時には「C:\SDL\lib」を追加して・・・ってやっているとコンパイル環境が変わった時に修正するのが面倒。一箇所変更するだけで全部変わってくれないかなーいやできるはずだよねーとやってみたら、ちょっと詰まったのでメモ。

  • 上級者モードに変更する
    • メニューバーの「ツール」「設定」「上級者モード」をクリック
    • 今まで隠れてたメニューが表示されるようになる
  • メニューバーから「表示」「プロパティーマネージャ」
  • プロジェクトの部分を右クリックし「プロパティシートの追加」
  • 適当な名前をつけてプロパティシートを作成
  • 追加したプロパティシートを開く
  • 「共通プロパティ」「ユーザマクロ」を選択
  • あとは見ればわかる

例えばこのユーザマクロに名前「SDLPATH」値「C:\SDL」と書いておくと、ヘッダーのパスは「$(SDLPATH)\include」、ライブラリのパスは「$(SDLPATH)\lib」と書ける。万が一変更があってもユーザマクロを書き換えればOK。

色々調べてやってみたけど、まず一番初めのステップで詰まった。

PerlでShiftJISを読み込もうとしたらデコードできないと言われた件について

2chの過去ログで遊ぼうとPerlを使っていじっていたのです。
2chのファイルはShift-JISで書かれているわけですが、文字コードの違いとか面倒なのでPerlのIOレイヤを使ってUTF-8へ変換しようと

open my $datfile, "<:encoding(shift-jis)", "000000000.dat";
while(my $line=<$datfile>) {
    print $dat;
}

みたいな感じのプログラムを書いて変換してみた。

するとこんな警告でいっぱいになってしまったのです・・・。


shiftjis "\xF6" does not map to Unicode at adddat.pl line 55, <$datfile> line 39.
shiftjis "\xF7" does not map to Unicode at adddat.pl line 55, <$datfile> line 39.
shiftjis "\xF7" does not map to Unicode at adddat.pl line 55, <$datfile> line 39.
shiftjis "\xF6" does not map to Unicode at adddat.pl line 55, <$datfile> line 39.
shiftjis "\x87" does not map to Unicode at adddat.pl line 55, <$datfile> line 45.
shiftjis "\x87" does not map to Unicode at adddat.pl line 55, <$datfile> line 45.
shiftjis "\x87" does not map to Unicode at adddat.pl line 55, <$datfile> line 45.
shiftjis "\x87" does not map to Unicode at adddat.pl line 55, <$datfile> line 45.

F6とか87で始まるこの文字何・・・?

と思って調べてみると・・・Windowsの拡張文字・・・!お前か!

①みたいな囲み文字とか、㍍みたいな組み文字たちですね。(ちなみにUnicodeでは国際規格で定義されているのでちゃんと表示されるはず)

Windowsの文字コードは拡張文字を含むので厳密にはShift-JISではありません。
MS932と呼ばれるそうです。
きっとPerlでもこの名前で使えるはず!

open my $datfile, "<:encoding(MS932)", "000000000.dat";
while(my $line=<$datfile>) {
    print $dat;
}

いくつか警告はでるけど、だいぶ少なくなったからよしとしましょう。

ICUとesaxxで極大部分文字列を求める

全ての部分文字列を考慮した文書分類」って論文の真似事をしてみようと、まずは極大部分文字列の抽出をやってみた。
極大部分文字列の作り方を調べていると、esaxxっていうライブラリが便利らしいとの情報を発見。(極大部分文字列 - アスペ日記)

早速やってみたわけだけど、サンプルでは文字型がcharなので、日本語を扱うことができない。僕は日本人だから日本語使うんだ!ってことで、C++JavaUnicodeライブラリ「ICU」で文字分割。ICUの名前は聞いたことあるけど、使うのは初めて。普通に


./configure
make
make all

ってしたら使えるようになりました。
ICU(C++)を使って Unicode 正規化 - やた@はてな日記」とか「ICUを使う | Netsphere Laboratories」を参考に、文字分割。その後esaxxに突っ込んでみた。

#include <iostream>
#include <vector>
#include <string>

#include <unicode/unistr.h>
#include <unicode/uchar.h>
#include <unicode/schriter.h>

#include "esa.hxx"

using namespace std;

int main() {
  vector<UChar32> T;
  while(!cin.eof()) {
    string s;
    getline(cin, s);

    UnicodeString str(s.c_str(), "UTF-8");
    StringCharacterIterator it(str);
    for(UChar32 uc = it.first32(); uc != it.DONE; uc = it.next32()) {
      if(uc>' ') T.push_back(uc);
    }
  }
 
  int n = T.size();

  vector<int>  SA(n);     // suffix array
  vector<int>  L (n);     // left boundaries of internal node
  vector<int>  R (n);     // right boundaries of internal node 
  vector<int>  D (n);     // depths of internal node
  
  int alphaSize = 0x110000;  // This can be very large
 int nodeNum = 0;
 if (esaxx(T.begin(), SA.begin(),
	   L.begin(), R.begin(),  D.begin(),
	   n, alphaSize, nodeNum) == -1){
   return -1;
 }

 vector<int> rank(n);
 int r = 0;
 for(int i=0;i<n;i++) {
   if(i==0 || T[(SA[i]+n-1)%n] != T[(SA[i-1]+n-1)%n]) r++;
   rank[i] = r;
   }

 for (int i = 0; i < nodeNum; ++i){
   // the frequency of substrings corresponding to the internal node
   //   and the depth of the internal node
   cout << R[i] - L[i] << "\t"  << D[i] << "\t"; 
   int beg = SA[L[i]];
   int len = D[i];
   for (int j = 0; j < len; ++j){
     UnicodeString us(T[beg + j]);
     char buf[8];
     us.extract(0, us.length(), buf, sizeof(buf), "UTF-8");
     cout << buf;
   }
   if(rank[ R[i] - 1 ] - rank[ L[i] ]>0) {
     cout << "*";
   }
   cout << endl;
   }
 return 0;
}

ICUとのリンクが必要なのでコンパイル時にオプション追加。


$ g++ `icu-config --cppflags --ldflags` program.cpp


$ ./a.out
うなぎうなうなうなぎ
^D
2 4 うなうな*
2 3 うなぎ*
4 2 うな*
2 5 ぎうなうな*
3 3 ぎうな*
2 2 なぎ
6 1 ぎ*
10 0 *

実行するとノード一覧が出力される。「*」が付いているのが極大部分文字列。「なぎ」は「うなぎ」の一部としてしか現れないから、極大部分文字列ではないと。なるほど。

シリアル通信のラッパー書いてみた

WindowsでもLinuxでも使えるシリアル通信ラッパー書いてみた。

ロボットにPC載せて、もっと賢いことをしてみようと計画中。これをやろうとすると、PCと周辺機器との通信が必要になるわけですね。方法はいろあるのでしょうが、最近大活躍のFT232RLを使ってUSB-シリアル変換するのが一番お手軽そう。

PCの環境としてはRTミドルウェアを検討中。RTミドルウェア自体はWindowsでもLinuxでも動くから、自分の書いた部分もどっちでも動くようにしたいな。ってことで適当ラッパー。


参考

#include <iostream>
#include <string>
#include <sstream>

#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#else
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
typedef int HANDLE;
#endif

class SerialPort {
	HANDLE hCom;

public:
	SerialPort(int port, int baudRate/*, int parity, int dataBits, int stopBits*/) {
#if defined(_WIN32) || defined(_WIN64)
		std::wostringstream comName;
		comName << "\\\\.\\COM" << port;
		hCom = CreateFile(comName.str().c_str(), GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
		if(hCom==INVALID_HANDLE_VALUE)
			throw new std::ios_base::failure("cannot open com port");

		DCB dcb;
		GetCommState(hCom, &dcb);

		dcb.BaudRate = baudRate;
		SetCommState(hCom, &dcb);
#else
		std::ostringstream comName;
		comName << "/dev/ttyS" << port;
		hCom = open(comName.str().c_str(),O_RDWR|O_NOCTTY);
		if(hCom==-1)
			throw new std::ios_base::failure("cannot open com port");
		
		struct termios tty;
		memset(&tty,0,sizeof(tty));
		tty.c_cflag=CS8|CLOCAL|CREAD;
		tty.c_cc[VMIN]=1;
		tty.c_cc[VTIME]=0;
		cfsetospeed(&tty, baudRate);
		cfsetispeed(&tty, baudRate);
		tcflush(hCom,TCIFLUSH);
		tcsetattr(hCom,TCSANOW,&tty);
#endif
	}

	int read(unsigned char *buf, int size) {
#if defined(_WIN32) || defined(_WIN64)
		DWORD rcv_size;
		if(!ReadFile(hCom, buf, size, &rcv_size, NULL))
			throw new std::ios_base::failure("Failed to read serial port");
		return (int)rcv_size;
#else
		return ::read(hCom, (void*)buf, size);
#endif
	}

	int write(unsigned char *buf, int size) {
#if defined(_WIN32) || defined(_WIN64)
		DWORD xmit_size;
		if(!WriteFile(hCom, buf, size, &xmit_size, NULL))
			throw new std::ios_base::failure("Failed to write serial port");
		return (int)xmit_size;
#else
		return ::write(hCom, (void*)buf, size);
#endif
	}

	~SerialPort() {
#if defined(_WIN32) || defined(_WIN64)
		CloseHandle(hCom);
		hCom = NULL;
#else
		close(hCom);
#endif
	}
};

int main(void) {
	SerialPort port(19, 9600);
	unsigned char a[10] = {0,1,2,3,4,5,6,7,8,9};
	for(int i=0;i<1000;i++) port.write(a, sizeof(a));
	return 0;
}