Arduino簡介
Twitter Backup Script 4
05/19/2010, 13:50 - Open Source
說不改,結果還是動手了啊...Qrz,加了將 URL 連結 tag 出來,比較方便直接點閱。
#!/bin/sh
#
USER=Tasuka
DATE=`date +%m%d%y-%H%M`
TIMEZONE=CST
TIMESHIFT=8
#
export all_proxy="http://proxy.ncu.edu.tw:3128"
#
FILENAME=twitter_backup
SUFFIX=html
#
FILE=$FILENAME.$SUFFIX
BACKUP_FILE=$FILENAME.1.$SUFFIX
#
if [ -f $FILE ];then
LAST=`cat $FILE | \
grep "META NAME" | \
grep "TWITTES" | \
awk -F" " '{print $3}' | \
awk -F"=" '{print $2}' | \
awk -F"\"" '{print $2}' \
`
LASTID=`cat $FILE | \
grep "META NAME" | \
grep "ID" | \
awk -F" " '{print $3}' | \
awk -F"=" '{print $2}' | \
awk -F"\"" '{print $2}' \
`
mv $FILE $BACKUP_FILE
else
LAST=0
LASTID=0
fi
MAX=`curl "http://api.twitter.com/1/statuses/user_timeline/$USER.xml?page=1&count=20" | \
grep "<statuses_count>" | \
awk -F">" '{print $2}' | \
awk -F"<" '{print $1}' | \
sort -u| \
awk 'BEGIN{ \
i=0; \
j=0 \
} \
{ \
j=$1; \
if (j>i) \
i=j \
} \
END { \
print i \
} \
' \
`
MAX_ID=`curl "http://api.twitter.com/1/statuses/user_timeline/$USER.xml?page=1&count=20" | \
grep "<id>" | \
awk -F">" '{print $2}' | \
awk -F"<" '{print $1}' | \
sort -u | \
awk 'BEGIN { \
i=0; \
j=0 \
} \
{ \
j=$1; \
if (j>i) \
i=j \
} \
END { \
print i \
} \
' \
`
if [ $LAST == 0 ];then
if [ $MAX -ge 3200 ];then
COUNTER=3200
else
COUNTER=$MAX
fi
PAGE=$((COUNTER%200))
if [ $PAGE != 0 ];then
PAGE=$((COUNTER/200))
PAGE=$((PAGE+1))
else
PAGE=$((COUNTER/200))
fi
echo "<HTML LANG=UTF8>" > $FILE
echo "<META NAME=\"TWITTES\" CONTENT=\"$MAX\">" >> $FILE
echo "<META NAME=\"ID\" CONTENT=\"$MAX_ID\">" >> $FILE
echo "<HEAD><TITLE>$USER@Twitter Backup Since $DATE</TITLE></HEAD><BODY>" >> $FILE
echo "<H1><A HREF=http://twitter.com/$USER>@$USER</A>'s Twitter Backup Since $DATE</H1>
<H4>$MAX Tweets</H4><BR>" >> $FILE
echo "<H4>" >> $FILE
i=1
while [ $i -le $PAGE ]; do
curl "http://api.twitter.com/1/statuses/user_timeline/$USER.xml?page=$i&count=200" | \
sed -e "/<text>/N;/<\/text>$/s/\n/ /g" -e "/>/s/>/</g" | \
awk -F"<" 'BEGIN{ flag=0;T=8; } \
{ \
if($2=="status" && flag==1){ \
flag=0 \
} \
if($2=="created_at" && flag==0){ \
split($3,datetime," "); \
year=datetime[6]; \
day=datetime[3]; \
if(datetime[2]=="Jan"){ \
month=1; \
md=31; \
}else \
if(datetime[2]=="Feb"){ \
month=2; \
if(year%4==0 && year%100!=0 || year%400==0){ \
md=29; \
}else{ \
md=28; \
} \
}else \
if(datetime[2]=="Mar"){ \
month=3; \
md=31; \
}else \
if(datetime[2]=="Apr"){ \
month=4; \
md=30; \
}else \
if(datetime[2]=="May"){ \
month=5; \
md=31; \
}else \
if(datetime[2]=="Jun"){ \
month=6; \
md=30; \
}else \
if(datetime[2]=="Jul"){ \
month=7; \
md=31; \
}else \
if(datetime[2]=="Aug"){ \
month=8; \
md=31; \
}else \
if(datetime[2]=="Sep"){ \
month=9; \
md=30; \
}else \
if(datetime[2]=="Oct"){ \
month=10; \
md=31; \
}else \
if(datetime[2]=="Nov"){ \
month=11; \
md=30; \
}else \
if(datetime[2]=="Dec"){ \
month=12; \
md=31; \
} \
split(datetime[4],time,":"); \
hour=((time[1]+T)%24); \
mins=time[2]; \
secs=time[3]; \
if((time[1]+T)%24==1){ \
day++; \
if(day/md==1){ \
day=day%md; \
month++; \
if(month/12==1){ \
month=month%12; \
year++; \
} \
} \
} \
printf "<P>\n %s-%s-%s %2s:%2s:%2s <BR>\n", \
year,month,day,hour,mins,secs \
} \
if($2=="text"){ \
printf "%s </P>\n",$3 \
} \
if($2=="user"){ \
flag=1 \
} \
}' | \
sed -e "/[hH][tT][tT][pP]:/s//http:/g" \
-e "/[hH][tT][tT][pP][sS]:/s//https:/g" \
-e "/[fF][tT][pT]:/s//ftp:/g" \
-e "s/http:\/\/[[:graph:]\.\/]*/<A HREF='&'>&<\/A> /g" \
-e "s/https:\/\/[[:graph:]\.\/]*/<A HREF='&'>&<\/A> /g" \
-e "s/ftp:\/\/[[:graph:]\.\/]*/<A HREF='&'>&<\/A> /g" >> $FILE
i=$((i+1))
done
echo "<CENTER><H6>Power with " >> $FILE
echo "<A HREF=http://www.gnu.org/software/gawk/>awk</A>," >> $FILE
echo "<A HREF=http://www.gnu.org/software/sed/>sed</A>," >> $FILE
echo "<A HREF=http://curl.haxx.se/>curl</A>," >> $FILE
echo "<A HREF=http://www.gnu.org/software/bash/>bash</A>" >> $FILE
echo "</H6></CENTER>" >> $FILE
echo "</BODY></HTML>" >> $FILE
else
COUNTER=$((MAX-LAST))
if [ $COUNTER != 0 ]; then
PAGE=$((COUNTER%200))
if [ $PAGE != 0 ];then
PAGE=$((COUNTER/200))
PAGE=$((PAGE+1))
else
PAGE=$((COUNTER/200))
fi
echo "<HTML LANG=UTF8>" > $FILE
echo "<META NAME=\"TWITTES\" CONTENT=\"$MAX\">" >> $FILE
echo "<META NAME=\"ID\" CONTENT=\"$MAX_ID\">" >> $FILE
echo "<HEAD><TITLE>$USER@Twitter Backup Since $DATE</TITLE></HEAD><BODY>" >> $FILE
echo "<H1><A HREF=http://twitter.com/$USER>@$USER</A>'s Twitter Backup Since $DATE</H1>
<H4>$MAX Tweets</H4><BR>" >> $FILE
echo "<H4>" >> $FILE
i=1
while [ $i -le $PAGE ]; do
curl "http://api.twitter.com/1/statuses/user_timeline/$USER.xml? \
since_id=$LASTID&page=$i&count=200" | \
sed -e "/<text>/N;/<\/text>$/s/\n/ /g" -e "/>/s/>/</g" | \
awk -F"<" 'BEGIN{ flag=0;T=8; } \
{ \
if($2=="status" && flag==1){ \
flag=0 \
} \
if($2=="created_at" && flag==0){ \
split($3,datetime," "); \
year=datetime[6]; \
day=datetime[3]; \
if(datetime[2]=="Jan"){ \
month=1; \
md=31; \
}else \
if(datetime[2]=="Feb"){ \
month=2; \
if(year%4==0 && year%100!=0 || year%400==0){ \
md=29; \
}else{ \
md=28; \
} \
}else \
if(datetime[2]=="Mar"){ \
month=3; \
md=31; \
}else \
if(datetime[2]=="Apr"){ \
month=4; \
md=30; \
}else \
if(datetime[2]=="May"){ \
month=5; \
md=31; \
}else \
if(datetime[2]=="Jun"){ \
month=6; \
md=30; \
}else \
if(datetime[2]=="Jul"){ \
month=7; \
md=31; \
}else \
if(datetime[2]=="Aug"){ \
month=8; \
md=31; \
}else \
if(datetime[2]=="Sep"){ \
month=9; \
md=30; \
}else \
if(datetime[2]=="Oct"){ \
month=10; \
md=31; \
}else \
if(datetime[2]=="Nov"){ \
month=11; \
md=30; \
}else \
if(datetime[2]=="Dec"){ \
month=12; \
md=31; \
} \
split(datetime[4],time,":"); \
hour=((time[1]+T)%24); \
mins=time[2]; \
secs=time[3]; \
if((time[1]+T)%24==1){ \
day++; \
if(day/md==1){ \
day=day%md; \
month++; \
if(month/12==1){ \
month=month%12; \
year++; \
} \
} \
} \
printf "<P>\n %s-%s-%s %2s:%2s:%2s <BR>\n", \
year,month,day,hour,mins,secs \
} \
if($2=="text"){ \
printf "%s </P>\n",$3 \
} \
if($2=="user"){ \
flag=1 \
} \
}' | \
sed -e "/[hH][tT][tT][pP]:/s//http:/g" \
-e "/[hH][tT][tT][pP][sS]:/s//https:/g" \
-e "/[fF][tT][pT]:/s//ftp:/g" \
-e "s/http:\/\/[[:graph:]\.\/]*/<A HREF='&'>&<\/A> /g" \
-e "s/https:\/\/[[:graph:]\.\/]*/<A HREF='&'>&<\/A> /g" \
-e "s/ftp:\/\/[[:graph:]\.\/]*/<A HREF='&'>&<\/A> /g" >> $FILE
i=$((i+1))
done
cat $BACKUP_FILE | \
sed -e "/^<HTML/d" \
-e "/^<META/d" \
-e "/^<HEAD>/d" \
-e "/^<H1>/d" \
-e "/^<H4>/d" >> $FILE
fi
fi
if [ $COUNTER == 0 ];then
mv $BACKUP_FILE $FILE
fi
Twitter Backup Script 3
05/18/2010, 14:35 - Open Source
這個版本,可以自動判斷新的 Twittes 而不會全部再 download 一次了。將這次的推數資料和ID放在HTML 的 META tag 中,以方便下次使用。要用的話,要將 USER= 換成自已的 Twitter Screen Name 這個 Script 就可以放到 Cron 中每個月自已備份一次了。
#!/bin/sh
#
USER=Tasuka
DATE=`date +%m%d%y-%H%M`
#FILENAME=/tmp/twitter_backup.$DATE.html
FILENAME=twitter_backup
SUFFIX=html
#
FILE=$FILENAME.$SUFFIX
BACKUP_FILE=$FILENAME.1.$SUFFIX
#
if [ -f $FILE ];then
LAST=`cat $FILE | \
grep "TWITTES" | \
awk -F" " '{print $3}' | \
awk -F"=" '{print $2}' | \
awk -F"\"" '{print $2}' \
`
LASTID=`cat $FILE | \
grep "ID" | \
awk -F" " '{print $3}' | \
awk -F"=" '{print $2}' | \
awk -F"\"" '{print $2}' \
`
mv $FILE $BACKUP_FILE
else
LAST=0
LASTID=0
fi
MAX=`curl "http://api.twitter.com/1/statuses/user_timeline/$USER.xml?page=1&count=20" | \
grep "<statuses_count>" | \
awk -F">" '{print $2}' | \
awk -F"<" '{print $1}' | \
sort -u| \
awk 'BEGIN{ \
i=0; \
j=0 \
} \
{ \
j=$1; \
if (j>i) \
i=j \
}
END { \
print i \
} \
' \
`
MAX_ID=`curl "http://api.twitter.com/1/statuses/user_timeline/$USER.xml?page=1&count=20" | \
grep "<id>" | \
awk -F">" '{print $2}' | \
awk -F"<" '{print $1}' | \
sort -u | \
awk 'BEGIN { \
i=0; \
j=0 \
} \
{ \
j=$1; \
if (j>i) \
i=j \
} \
END { \
print i \
} \
' \
`
if [ $LAST == 0 ];then
if [ $MAX -ge 3200 ];then
COUNTER=3200
else
COUNTER=$MAX
fi
PAGE=$((COUNTER%200))
if [ $PAGE != 0 ];then
PAGE=$((COUNTER/200))
PAGE=$((PAGE+1))
else
PAGE=$((COUNTER/200))
fi
echo "<HTML LANG=UTF8>" > $FILE
echo "<META NAME=\"TWITTES\" CONTENT=\"$MAX\">" >> $FILE
echo "<META NAME=\"ID\" CONTENT=\"$MAX_ID\">" >> $FILE
echo "<HEAD><TITLE>$USER@Twitter Backup Since $DATE</TITLE></HEAD><BODY><H3>" >> $FILE
i=1
while [ $i -le $PAGE ]; do
curl "http://api.twitter.com/1/statuses/user_timeline/$USER.xml?page=$i&count=200" | \
sed -e "/<text>/N;/<\/text>$/s/\n/ /g" -e "/>/s/>/</g" | \
awk -F"<" 'BEGIN{ flag=0 } \
{ \
if($2=="status" && flag==1){ \
flag=0 \
} \
if($2=="created_at" && flag==0){ \
printf "<BR>%s<BR>",$3 \
} \
if($2=="text"){ \
printf "%s<BR>",$3 \
} \
if($2=="user"){ \
flag=1 \
} \
}' | \
sed -e "/+0000/s/+0000//g" >> $FILE
i=$((i+1))
done
echo "</BODY></HTML>" >> $FILE
else
COUNTER=$((MAX-LAST))
if [ $COUNTER != 0 ]; then
PAGE=$((COUNTER%200))
if [ $PAGE != 0 ];then
PAGE=$((COUNTER/200))
PAGE=$((PAGE+1))
else
PAGE=$((COUNTER/200))
fi
echo "<HTML LANG=UTF8>" > $FILE
echo "<META NAME=\"TWITTES\" CONTENT=\"$MAX\">" >> $FILE
echo "<META NAME=\"ID\" CONTENT=\"$MAX_ID\">" >> $FILE
echo "<HEAD><TITLE>$USER@Twitter Backup Since $DATE</TITLE></HEAD><BODY><H3>" >> $FILE
i=1
while [ $i -le $PAGE ]; do
curl "http://api.twitter.com/1/statuses/user_timeline/$USER.xml?
since_id=$LASTID&page=$i&count=200" | \
sed -e "/<text>/N;/<\/text>$/s/\n/ /g" -e "/>/s/>/</g" | \
awk -F"<" 'BEGIN{ flag=0 } \
{ \
if($2=="status" && flag==1){ \
flag=0 \
} \
if($2=="created_at" && flag==0){ \
printf "<BR>%s<BR>",$3 \
} \
if($2=="text"){ \
printf "%s<BR>",$3 \
} \
if($2=="user"){ \
flag=1 \
} \
}' | \
sed -e "/+0000/s/+0000//g" >> $FILE
i=$((i+1))
done
cat $BACKUP_FILE | \
sed -e "/<HTML/d" -e "/META/d" -e "/<HEAD>/d" >> $FILE
fi
fi
if [ $COUNTER == 0 ];then
mv $BACKUP_FILE $FILE
fi
Twitter Backup Script 2
05/15/2010, 14:45 - Open Source
修改加上日期及在 META 中放上 Twitts 數量,以備後用。我的 Twitter 備份
#!/bin/sh
#
USER=Tasuka
DATE=`date +%m%d%y`
FILENAME=/tmp/twitter_backup.$DATE.html
#
MAX=`curl "http://api.twitter.com/1/statuses/user_timeline/$USER.xml?page=1&count=20" | \
grep "<statuses_count>" | \
awk -F">" '{print $2}' | \
awk -F"<" '{print $1}' | \
sort | \
awk '{if ($1>NF) NF=$1} END {print NF}'`
if [ $MAX -ge 3200 ];then
MAX=3200
fi
PAGE=$((MAX%200))
if [ $PAGE != 0 ];then
PAGE=$((MAX/200))
PAGE=$((PAGE+1))
else
PAGE=$((MAX/200))
fi
echo "<HTML LANG=UTF8><META NAME=\"TWITTES\" CONTENT=\"$MAX\"> \
<HEAD><TITLE>$USER@Twitter Backup</TITLE></HEAD><BODY><H3>" > \
$FILENAME
i=1
while [ $i -le $PAGE ]; do
curl "http://api.twitter.com/1/statuses/user_timeline/$USER.xml?page=$i&count=200" | \
sed -e "/>/s/>/</g" | \
awk -F"<" 'BEGIN{ flag=0 } \
{ \
if($2=="status" && flag==1){ \
flag=0 \
} \
if($2=="created_at" && flag==0){ \
printf "<BR>%s<BR>",$3 \
} \
if($2=="text"){ \
printf "%s<BR>",$3 \
} \
if($2=="user"){ \
flag=1 \
} \
}' | \
sed -e "/+0000/s/+0000//g" >> $FILENAME
i=$((i+1))
MAX=$((MAX-1))
done
echo "</BODY></HTML>" >> $FILENAME
Twitter Backup Script
05/13/2010, 22:48 - Open Source
上次看了 hao520 在 Twitter 和他的 blog 中談到 Twitter 有可視最後3200推的數量問題,連帶而來的備份的問題。看了還真的有人在作 backup,hao520自已也做了一個 script,不過他是直接從 twitter 的網頁拿資料。一時技癢就也自已作了一個 bash script,是經由 twitter API 而來的。目前顯示出來的資料,沒有編號、也沒有日期,所以還有改善的空間。以下是備份下來的HTML內容:

再來是程式碼
#!/bin/sh
#
USER=Tasuka
#
MAX=`curl "http://api.twitter.com/1/statuses/user_timeline/$USER.xml?page=1&count=20" \
|grep "<statuses_count>"|awk -F">" '{print $2}' \
|awk -F"<" '{print $1}'|sort| \
awk '{if ($1>NF) NF=$1} END {print NF}'`
if [ $MAX -ge 3200 ];then
MAX=3200
fi
PAGE=$((MAX%200))
if [ $PAGE != 0 ];then
PAGE=$((MAX/200))
PAGE=$((PAGE+1))
else
PAGE=$((MAX/200))
fi
i=1
DATE=`date +%m%d%y-%H%M`
echo "<HTML LANG=UTF8><HEAD><TITLE>$USER Twitter Backup</TITLE> \
</HEAD><BODY><H3>" > /tmp/twitter_backup.$DATE.html
while [ $i -le $PAGE ]; do
curl "http://api.twitter.com/1/statuses/user_timeline/$USER.xml?page=$i&count=200" \
|grep '<text>' | awk -F"<text>" '{print $2}' | \
awk -F"</text>" '{printf "%s<BR>",$1}' >>/tmp/twitter_backup.$DATE.html
i=$((i+1))
MAX=$((MAX-1))
done
echo "</BODY></HTML>" >>/tmp/twitter_backup.$DATE.html
BCH(15,5) Error Correction for Objective-C
04/13/2010, 22:02 - Open Source
BCH(15,5) class for Objective-C。參考 http://en.wikipedia.org/wiki/BCH_code這個 class 說起也不算是我寫的,是修改 Masayuki Miyazaki 寫的 QRCode Java 程式中的 BCH_15_5.java 片斷,只是簡單的改成 Objective-C 而已。
//
// BCH_15_5.h
// BCHTest
//
// Created by Tasuka Hsu on 04/13/2010.
// Copyleft 2010 http://Tasuka.IDV.TW.
//
#import <Foundation/Foundation.h>
@interface BCH_15_5 : NSObject {
}
-(unsigned int)encode:(unsigned int)data;
-(unsigned int)decode:(unsigned int)data;
@end
//
// BCH_15_5.m
// BCHTest
//
// Created by Tasuka Hsu on 04/13/2010.
// Copyleft 2010 http://Tasuka.IDV.TW.
//
// Based on Masayuki Miyazaki
// http://sourceforge.jp/projects/reedsolomon/
#import "BCH_15_5.h"
#define TABLE_SIZE 32
@interface BCH_15_5 (Private)
const unsigned int GX=0x137; /* 0000000100110111 */
unsigned int *trueCodes=NULL;
-(void)makeTrueCodes;
-(unsigned int)slowEncode:(unsigned int)data;
-(int)calcDistance:(unsigned int)c1:(unsigned int)c2;
@end
@implementation BCH_15_5
-(id)init
{
if(![super init]){
return nil;
}
if((trueCodes=(unsigned int *)malloc(TABLE_SIZE*sizeof(unsigned int)))==NULL){
return nil;
}
[self makeTrueCodes];
return self;
}
-(void)dealloc
{
if(trueCodes!=NULL){
free(trueCodes);
}
[super dealloc];
}
-(void)makeTrueCodes
{
for(int i=0;i<TABLE_SIZE;i++){
trueCodes=[self slowEncode:i];
}
}
-(unsigned int)slowEncode:(unsigned int)data
{
unsigned int wk=0;
data<<=5;
for(int i=0;i<5;i++){
wk<<=1;
data<<=1;
if(((wk^data)&0x400)!=0){
wk^=GX;
}
}
return(data&0x7c00)|(wk&0x3ff);
}
-(unsigned int)encode:(unsigned int)data
{
return trueCodes[data&0x1f];
}
-(unsigned int)decode:(unsigned int)data
{
data&=0x7fff;
for(int i=0;i<TABLE_SIZE;i++){
unsigned int code=trueCodes;
if([self calcDistance:data:code]<=3){
return code;
}
}
return -1;
}
-(int)calcDistance:(unsigned int)c1:(unsigned int)c2
{
int n=0;
unsigned int wk=c1^c2;
while(wk!=0) {
if((wk&1)!=0){
n++;
}
wk>>=1;
}
return n;
}
@end
#import <Foundation/Foundation.h>
#import "BCH_15_5.h"
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
unsigned int i,j,k,c=19;
BCH_15_5 *bche=[[BCH_15_5 alloc] init];
i=[bche encode:c];
k=i;
printf("BCH_15_5 encode %d",c);
printf(" 0b");
for(int j=0;j<15;j++){
printf("%1d",((i<<=1)&0x8000)?1:0);
}
printf("\n");
[bche release];
// Add random noise
srandom(time(NULL));
unsigned int n=random();
switch(n%3){
case 0:
n&=0x000f;
break;
case 1:
n&=0x00f0;
break;
case 2:
n&=0x0f00;
break;
case 3:
n&=0xf000;
break;
default:
break;
}
printf("add noise=0x%x\n",n);
k^=n;
BCH_15_5 *bchd=[[BCH_15_5 alloc] init];
i=[bchd decode:k];
printf("BCH_15_5 decode 0x%x correct 0x%x\n",k,i);
k=i;
printf("0b");
for(j=0;j<15;j++){
printf("%1d",((i<<=1)&0x8000)?1:0);
}
printf("\n");
k&=0xfd00;
i=k;
printf("Code is 0b");
for(j=0;j<5;j++){
printf("%1d",((i<<=1)&0x8000)?1:0);
}
k>>=10;
printf(" %d\n",k);
[bchd release];
[pool drain];
return 0;
}
rscode-objc project in GoogleCode
03/26/2010, 16:51 - Open Source
因為想要做點有趣的實驗,會用到 ReedSolomon FEC 演算法, 網路上有 Java 或 C 版本,但沒找到 Objective-C 可直接用的程式碼.
所以就花了一點時間,參考了 Java 和 C 的版本,做了一個 Objective-C 的版本
給 XCode 在 OS X 下使用,並放到 GoogleCode 上作管理.
原來是想直接用 C 的版本,但在改寫的過程中, 發現原來的程式用了很多的 for loop,
及使用了 array 的資料形態.
後來修改為使用 pointer 和 malloc 動態使用記憶體,並用 memset 和 memcpy 減少了 for loop 的使用.
這個 class 應該可以不用修改就可以經由 GNUStep 搬到各個平台下使用.
想要帶回家玩的可以用 svn checkout http://rscode-objc.googlecode.com/svn/trunk/ rscode-objc-read-only 到 GoogleCode 的 svn 下載
原本 C 語言版本的 rscode 是版權是 GPL, 而商業版要收費的, 而我只是修改, 所以也算是 GPL.
不過我想不收錢, 應該也收不到錢, 因為只是修改,所以也不能收錢.
有注意看的話,在程式開頭權利宣告我是用 Copyleft 而不是 Copyright. XD.
參考資料
http://reedsolomon.sourceforge.jp Java 版 ReedSolomon
http://rscode.sourceforge.net C 語言版本.
http://rscode-objc.googlecode.com GoogleCode Project
程式
RSEncodeDecode.h
//
// RSEncodeDecode.h
// RSCode
//
// Created by Tasuka Hsu on 03/25/2010.
// Copyleft 2010 http://Tasuka.IDV.TW.
// Original C Source code is from http://rscode.sourceforge.net
// and reference to Java Source code from http://reedsolomon.sourceforge.jp
#import <Foundation/Foundation.h>
#import <stdio.h>
#import <stdlib.h>
#define PPOLY 0x1d
/*
Below is NPAR, the only compile-time parameter you should have to
modify.
It is the number of parity bytes which will be appended to
your data to create a codeword.
Note that the maximum codeword size is 255, so the
sum of your message length plus parity should be less than
or equal to this maximum limit.
In practice, you will get slooow error correction and decoding
if you use more than a reasonably small number of parity bytes.
(say, 10 or 20)
*/
#define NPAR 17
/* Maximum degree of various polynomials. */
#define MAXDEG (NPAR*2)
#define TABLESIZE 256
@interface RSEncodeDecode : NSObject {
@public
int npar;
int maxdeg;
int length;
int *gExp;
int *gLog;
// Encoder parity bytes
int *pBytes;
// Decoder syndrome bytes
int *synBytes;
// generator polynomial
int *genPoly;
// The Error Locator Polynomial, also known as Lambda or Sigma. Lambda[0]==1
int *Lambda;
// The Error Evaluator Polynomial
int *Omega;
@private
// error locations found using Chien's search
int *ErrorLocs;
int NErrors;
// erasure flags
int *ErasureLocs;
int NErasures;
}
-(void)setNPAR:(int)n;
-(void)setLength:(int)n;
-(BOOL)initTables;
-(void)freeTables;
// Reed Solomon encode/decode routines
-(void)initializeECC;
-(int)checkSyndrome;
-(void)deCode:(unsigned char *)data:(int)l;
-(void)deCode:(unsigned char *)data;
-(void)deCode:(unsigned char *)data:(int)l:(int)n;
-(void)enCode:(unsigned char *)msg:(int)l:(unsigned char *)dst;
-(void)enCode:(unsigned char *)msg:(unsigned char *)dst;
-(void)enCode:(unsigned char *)msg:(int)l:(unsigned char *)dst:(int)nl;
// CRC-CCITT checksum generator
-(short int)crcCCITT:(unsigned char *)msg:(int)len;
-(short int)crcHWare:(short int)data:(short int)genpoly:(short int)accum;
-(void)initGaloisTables;
-(int)gInv:(int)a;
-(int)gMul:(int)a:(int)b;
/* Error location routines */
-(int)correctErrorsErasures:(unsigned char *)codeword:(int)csize:(int)nerasures:(int *)erasures;
-(void)modifiedBerlekampMassey;
/* polynomial arithmetic */
-(void)addPolys:(int *)dst:(int *)src;
-(void)scalePoly:(int)k:(int *)poly;
-(void)mulPolys:(int *)dst:(int *)p1:(int *)p2;
-(void)copyPoly:(int *)dst:(int *)src;
-(void)zeroPoly:(int *)poly;
-(void)findRoots;
/* local ANSI declarations */
-(int)computeDiscrepancy:(int *)lambda:(int *)S:(int)L:(int)n;
-(void)computeGenPoly:(int)l:(int *)genpoly;
-(void)initGamma:(int *)gamma;
-(void)computeModifiedOmega;
-(void)computeNextOmega:(int)d:(int *)A:(int *)dst:(int *)src;
-(void)mulzPoly:(int *)src;
-(void)zeroFillFrom:(unsigned char *)buf:(int)from:(int)to;
// debugging routines
-(void)printParity;
-(void)printSyndrome;
@end
RSEncodeDecode.m
//
// RSEncodeDecode.m
// RSCode
//
// Created by Tasuka Hsu on 03/25/2010.
// Copyrleft 2010 http://Tasuka.IDV.TW.
// Original C Source code from http://rscode.sourceforge.net
// and reference to Java Source code from http://reedsolomon.sourceforge.jp
#import "RSEncodeDecode.h"
@implementation RSEncodeDecode
/* This is one of 14 irreducible polynomials
* of degree 8 and cycle length 255. (Ch 5, pp. 275, Magnetic Recording)
* The high order 1 bit is implicit */
/* x^8 + x^4 + x^3 + x^2 + 1 */
-(id)init
{
if(![super init]){
return nil;
}
npar=NPAR;
maxdeg=npar*2;
length=0;
if([self initTables]!=TRUE){
NSLog(@"Memory allocated error\n");
return nil;
}
[self initializeECC];
return self;
}
-(void)dealloc
{
[self freeTables];
[super dealloc];
}
-(void)setNPAR:(int)n
{
npar=n;
maxdeg=npar*2;
[self freeTables];
if([self initTables]!=TRUE){
NSLog(@"Memory allocated error\n");
return;
}
[self initializeECC];
}
-(void)setLength:(int)n
{
length=n;
}
-(BOOL)initTables
{
if((gExp=(int *)malloc(sizeof(int)*TABLESIZE*2))==NULL){
return FALSE;
}
if((gLog=(int *)malloc(sizeof(int)*TABLESIZE))==NULL){
free(gExp);
return FALSE;
}
if((pBytes=(int *)malloc(sizeof(int)*maxdeg))==NULL){
free(gExp);
free(gLog);
return FALSE;
}
if((synBytes=(int *)malloc(sizeof(int)*maxdeg))==NULL){
free(gExp);
free(gLog);
free(pBytes);
return FALSE;
}
if((Lambda=(int *)malloc(sizeof(int)*maxdeg))==NULL){
free(gExp);
free(gLog);
free(pBytes);
free(synBytes);
return FALSE;
}
if((Omega=(int *)malloc(sizeof(int)*maxdeg))==NULL){
free(gExp);
free(gLog);
free(pBytes);
free(synBytes);
free(Lambda);
return FALSE;
}
if((genPoly=(int *)malloc(sizeof(int)*maxdeg*2))==NULL){
free(gExp);
free(gLog);
free(pBytes);
free(synBytes);
free(Lambda);
free(Omega);
return FALSE;
}
if((ErrorLocs=(int *)malloc(sizeof(int)*maxdeg*2))==NULL){
free(gExp);
free(gLog);
free(pBytes);
free(synBytes);
free(Lambda);
free(Omega);
free(genPoly);
return FALSE;
}
if((ErasureLocs=(int *)malloc(sizeof(int)*maxdeg*2))==NULL){
free(gExp);
free(gLog);
free(pBytes);
free(synBytes);
free(Lambda);
free(Omega);
free(genPoly);
free(ErrorLocs);
return FALSE;
}
return TRUE;
}
-(void)freeTables
{
if(gExp!=NULL){
free(gExp);
}
if(gLog!=NULL){
free(gLog);
}
if(pBytes!=NULL){
free(pBytes);
}
if(synBytes!=NULL){
free(synBytes);
}
if(Lambda!=NULL){
free(Lambda);
}
if(Omega!=NULL){
free(Omega);
}
if(genPoly!=NULL){
free(genPoly);
}
if(ErrorLocs!=NULL){
free(ErrorLocs);
}
if(ErasureLocs!=NULL){
free(ErasureLocs);
}
}
// Initialize lookup tables, polynomials, etc.
-(void)initializeECC
{
// Initialize the galois field arithmetic tables
[self initGaloisTables];
// Compute the encoder generator polynomial
[self computeGenPoly:npar:genPoly];
}
-(void)initGaloisTables
{
// initialize the table of powers of alpha
register int i,d=1;
for(i=0;i<TABLESIZE-1;i++){
gExp=gExp[TABLESIZE-1+i]=d;
gLog[d]=i;
d<<=1;
if((d&0x100)!=0){
d=(d^PPOLY)&0xff;
}
}
}
// multiplication using logarithms
-(int)gMul:(int)a:(int)b
{
return(((a==0)||(b==0))?0:(gExp[gLog[a]+gLog]));
}
-(int)gInv:(int)a
{
return(gExp[TABLESIZE-1-gLog[a]]);
}
// From Cain, Clark, "Error-Correction Coding For Digital Communications", pp. 216.
-(void)modifiedBerlekampMassey
{
register int i,n;
int L,L2,k,d;
int *psi,*psi2,*D,*gamma;
if((psi=(int *)malloc(sizeof(int)*maxdeg))==NULL){
return;
}
if((psi2=(int *)malloc(sizeof(int)*maxdeg))==NULL){
return;
}
if((D=(int *)malloc(sizeof(int)*maxdeg))==NULL){
return;
}
if((gamma=(int *)malloc(sizeof(int)*maxdeg))==NULL){
return;
}
// initialize Gamma, the erasure locator polynomial
[self initGamma:gamma];
// initialize to z
[self copyPoly:D:gamma];
[self mulzPoly:D];
[self copyPoly:psi:gamma];
k=-1;
L=NErasures;
for(n=NErasures;n<npar;n++){
d=[self computeDiscrepancy:psi:synBytes:L:n];
if(d!=0){
// psi2 = psi - d*D
for(i=0;i<maxdeg;i++){
psi2=psi^[self gMul:d:D];
}
if(L<(n-k)){
L2=n-k;
k=n-L;
// D = scalePoly(gInv(d), psi);
for(i=0;i<maxdeg;i++){
D=[self gMul:psi:[self gInv:d]];
}
L=L2;
}
memcpy(psi,psi2,maxdeg*sizeof(int));
}
[self mulzPoly:D];
}
memcpy(Lambda,psi,maxdeg*sizeof(int));
[self computeModifiedOmega];
free(psi);
free(psi2);
free(D);
free(gamma);
}
// given Psi (called Lambda in modifiedBerlekampMassey) and synBytes,
// compute the combined erasure/error evaluator polynomial as Psi*S mod z^4
-(void)computeModifiedOmega
{
int *product;
if((product=(int *)malloc(sizeof(int)*maxdeg*2))==NULL){
return;
}
[self mulPolys:product:Lambda:synBytes];
[self zeroPoly:Omega];
memcpy(Omega,product,npar*sizeof(int));
free(product);
}
/* polynomial multiplication */
-(void)mulPolys:(int *)dst:(int *)p1:(int *)p2
{
register int i,j;
int *tmp;
if((tmp=(int *)malloc(sizeof(int)*maxdeg*2))==NULL){
return;
}
memset(dst,0,maxdeg*2*sizeof(int));
for(i=0;i<maxdeg;i++){
memset((tmp+maxdeg),0,maxdeg*sizeof(int));
// scale tmp1 by p1
for(j=0;j<maxdeg;j++){
tmp[j]=[self gMul:p2[j]:p1];
}
// and mult (shift) tmp1 right by i
for(j=(maxdeg*2)-1;j>=i;j--){
tmp[j]=tmp[j-i];
}
memset(tmp,0,i*sizeof(int));
// add into partial product
for(j=0;j<(maxdeg*2);j++){
dst[j]^=tmp[j];
}
}
free(tmp);
}
// gamma = product (1-z*a^Ij) for erasure locs Ij
-(void)initGamma:(int *)gamma
{
register int i;
int *tmp;
if((tmp=(int *)malloc(sizeof(int)*maxdeg))==NULL){
return;
}
[self zeroPoly:gamma];
[self zeroPoly:tmp];
gamma[0]=1;
for(i=0;i<NErasures;i++){
[self copyPoly:tmp:gamma];
[self scalePoly:gExp[ErasureLocs]:tmp];
[self mulzPoly:tmp];
[self addPolys:gamma:tmp];
}
free(tmp);
}
-(void)computeNextOmega:(int)d:(int *)A:(int *)dst:(int *)src
{
register int i;
for(i=0;i<maxdeg;i++){
dst=src^[self gMul:d:A];
}
}
-(int)computeDiscrepancy:(int *)lambda:(int *)S:(int)L:(int)n
{
register int i,sum=0;
for(i=0;i<=L;i++){
sum^=[self gMul:lambda:S[n-i]];
}
return(sum);
}
// polynomial arithmetic
-(void)addPolys:(int *)dst:(int *)src
{
register int i;
for(i=0;i<maxdeg;i++){
dst^=src;
}
}
-(void)copyPoly:(int *)dst:(int *)src
{
memcpy(dst,src,maxdeg*sizeof(int));
}
-(void)scalePoly:(int)k:(int *)poly
{
register int i;
for(i=0;i<maxdeg;i++){
poly=[self gMul:k:poly];
}
}
-(void)zeroPoly:(int *)poly
{
memset(poly,0,maxdeg*sizeof(int));
}
// multiply by z, i.e., shift right by 1
-(void)mulzPoly:(int *)src
{
register int i;
for(i=maxdeg-1;i>0;i--){
src=src[i-1];
}
src[0]=0;
}
/* Finds all the roots of an error-locator polynomial with coefficients
* Lambda[j] by evaluating Lambda at successive values of alpha.
*
* This can be tested with the decoder's equations case.
*/
-(void)findRoots
{
int sum;
register int i,j;
NErrors=0;
for(i=1;i<TABLESIZE;i++){
sum=0;
// evaluate lambda at i
for(j=0;j<npar+1;j++){
sum^=[self gMul:gExp[(i*j)%(TABLESIZE-1)]:Lambda[j]];
}
if(sum==0){
ErrorLocs[NErrors]=(TABLESIZE-1-i);
NErrors++;
#ifdef DEBUG
fprintf(stderr,"Root found at i = %d, (255-i) = %d\n",i,(TABLESIZE-1-i));
#endif
}
}
}
/* Combined Erasure And Error Magnitude Computation
*
* Pass in the codeword, its size in bytes, as well as
* an array of any known erasure locations, along the number
* of these erasures.
*
* Evaluate Omega(actually Psi)/Lambda' at the roots
* alpha^(-i) for error locs i.
*
* Returns 1 if everything ok, or 0 if an out-of-bounds error is found
*
*/
-(int)correctErrorsErasures:(unsigned char *)codeword:(int)csize:(int)nerasures:(int *)erasures
{
int r,i,j,err;
int num,denom;
// If you want to take advantage of erasure correction, be sure to
// set NErasures and ErasureLocs[] with the locations of erasures.
NErasures=nerasures;
memcpy(ErasureLocs,erasures,NErasures);
[self modifiedBerlekampMassey];
[self findRoots];
if((NErrors<=npar)&&(NErrors>0)){
// first check for illegal error locs
for(r=0;r<NErrors;r++) {
if(ErrorLocs[r]>=csize){
#ifdef DEBUG
fprintf(stderr,"Error loc i=%d outside of codeword length %d\n",i,csize);
#endif
return(0);
}
}
for(r=0;r<NErrors;r++){
i=ErrorLocs[r];
// evaluate Omega at alpha^(-i)
num=0;
for(j=0;j<maxdeg;j++){
num^=[self gMul:Omega[j]:gExp[((TABLESIZE-1-i)*j)%(TABLESIZE-1)]];
}
// evaluate Lambda' (derivative) at alpha^(-i) ; all odd powers disappear
denom=0;
for(j=1;j<maxdeg;j+=2){
denom^=[self gMul:Lambda[j]:gExp[((TABLESIZE-1-i)*(j-1))%(TABLESIZE-1)]];
}
err=[self gMul:num:[self gInv:denom]];
#ifdef DEBUG
fprintf(stderr,"Error magnitude %#x at loc %d\n",err,csize-i);
#endif
codeword[csize-i-1]^=err;
}
return(1);
}else{
#ifdef DEBUG
if(NErrors){
fprintf(stderr,"Uncorrectable codeword\n");
}
#endif
return(0);
}
}
// models crc hardware (minor variation on polynomial division algorithm)
-(short int)crcHWare:(short int)data:(short int)genpoly:(short int)accum
{
register short int i;
data<<=8;
for(i=8;i>0;i--){
if((data^accum)&0x8000){
accum=((accum<<1)^genpoly)&0xFFFF;
}else{
accum=(accum<<1)&0xFFFF;
}
data=(data<<1)&0xFFFF;
}
return(accum);
}
// Computes the CRC-CCITT checksum on array of byte data, length len
-(short int)crcCCITT:(unsigned char *)msg:(int)len
{
register int i;
register short int acc=0;
for(i=0;i<len;i++){
acc=[self crcHWare:(short int)msg:(short int)0x1021:acc];
}
return(acc);
}
-(void)zeroFillFrom:(unsigned char *)buf:(int)from:(int)to
{
register int i;
for(i=from;i<to;i++){
buf=0;
}
}
// debugging routines
-(void)printParity
{
register int i;
printf("Parity Bytes: ");
for(i=0;i<npar;i++){
printf("[%d]:%x, ",i,pBytes);
}
printf("\n");
}
-(void)printSyndrome
{
register int i;
printf("Syndrome Bytes: ");
for(i=0;i<npar;i++){
printf("[%d]:%x, ",i,synBytes);
}
printf("\n");
}
// Append the parity bytes onto the end of the message
-(void)build_codeword:(unsigned char *)msg:(int)l:(unsigned char *)dst
{
register int i;
memcpy(dst,msg,l*sizeof(int));
for(i=0;i<npar;i++){
dst[i+l]=pBytes[npar-1-i];
}
}
/*
* Reed Solomon Decoder
*
* Computes the syndrome of a codeword. Puts the results
* into the synBytes[] array.
*/
-(void)deCode:(unsigned char *)data:(int)l
{
register int i,j;
int sum;
[self setLength:l];
for(j=0;j<npar;j++){
sum=0;
for(i=0;i<l;i++){
sum=data^[self gMul:gExp[j+1]:sum];
}
synBytes[j]=sum;
}
}
-(void)deCode:(unsigned char *)data
{
[self deCode:data:length];
}
-(void)deCode:(unsigned char *)data:(int)l:(int)n
{
[self setNPAR:n];
[self setLength:l];
[self deCode:data:length];
}
// Check if the syndrome is zero
-(int)checkSyndrome
{
register int i;
int nz=0;
for(i=0;i<npar;i++){
if(synBytes!=0){
nz=1;
break;
}
}
return nz;
}
-(void)debugCheckSyndrome
{
register int i;
for(i=0;i<3;i++){
printf(" inv log S[%d]/S[%d] = %d\n",i,i+1, \
gLog[[self gMul:synBytes:[self gInv:synBytes[i+1]]]]);
}
}
/* Create a generator polynomial for an n byte RS code.
* The coefficients are returned in the genPoly arg.
* Make sure that the genPoly array which is passed in is
* at least n+1 bytes long.
*/
-(void)computeGenPoly:(int)l:(int *)genpoly
{
register int i;
int *tp,*tp1;
if((tp=(int *)malloc(sizeof(int)*TABLESIZE))==NULL){
return;
}
if((tp1=(int *)malloc(sizeof(int)*TABLESIZE))==NULL){
return;
}
// multiply (x + a^n) for n = 1 to l
[self zeroPoly:tp1];
tp1[0]=1;
for(i=1;i<=l;i++){
[self zeroPoly:tp];
tp[0]=gExp; /* set up x+a^n */
tp[1]=1;
[self mulPolys:genpoly:tp:tp1];
[self copyPoly:tp1:genpoly];
}
free(tp);
free(tp1);
}
/* Simulate a LFSR with generator polynomial for n byte RS code.
* Pass in a pointer to the data array, and amount of data.
*
* The parity bytes are deposited into pBytes[], and the whole message
* and parity are copied to dest to make a codeword.
*
*/
-(void)enCode:(unsigned char *)msg:(int)l:(unsigned char *)dst
{
register int i,j;
int *LFSR,dbyte;
if((LFSR=(int *)malloc(sizeof(int)*(npar+1)))==NULL){
return;
}
memset(LFSR,0,npar*sizeof(int));
[self setLength:l];
for(i=0;i<l;i++){
dbyte=msg^LFSR[npar-1];
for(j=npar-1;j>0;j--){
LFSR[j]=LFSR[j-1]^[self gMul:genPoly[j]:dbyte];
}
LFSR[0]=[self gMul:genPoly[0]:dbyte];
}
memcpy(pBytes,LFSR,npar*sizeof(int));
[self build_codeword:msg:l:dst];
free(LFSR);
}
-(void)enCode:(unsigned char *)msg:(unsigned char *)dst
{
[self enCode:msg:length:dst];
}
-(void)enCode:(unsigned char *)msg:(int)l:(unsigned char *)dst:(int)n
{
[self setNPAR:n];
[self setLength:l];
[self enCode:msg:length:dst];
}
@end
測試程式
RSCode.m
// Created by Tasuka Hsu on 03/25/2010.
// Copyleft 2010 http://Tasuka.IDV.TW.
// Original C Source code is from http://rscode.sourceforge.net
#import <Foundation/Foundation.h>
#import "RSEncodeDecode.h"
#define ML (sizeof(msg)+NPAR)
// Introduce a byte error at LOC
void byte_err(int err,int loc,unsigned char *dst)
{
//printf("Adding Error at loc %d, data %#x\n",loc,dst[loc-1]);
dst[loc-1]^=err;
}
// Pass in location of error (first byte position is labeled starting at 1, not 0), and the codeword.
void byte_erasure(int loc,unsigned char *dst,int cwsize,int *erasures)
{
//printf("Erasure at loc %d, data %#x\n",loc,dst[loc-1]);
dst[loc-1]=0;
}
int main (int argc, const char * argv[]) {
NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
unsigned char msg[]="Learn from other people's mistakes, you do'nt have time to make your own.";
unsigned char codeword[TABLESIZE];
int erasures[16];
int nerasures=0;
// Initialize RSCode Encode Decode Object
RSEncodeDecode *RS=[[RSEncodeDecode alloc] init];
[RS setNPAR:17];
[RS setLength:sizeof(msg)];
// Encode data into codeword, adding NPAR parity bytes
//[RS enCode:msg:sizeof(msg):codeword];
[RS enCode:msg:codeword];
printf("Encoded data is: \"%s\"\n",codeword);
// Add errors and two erasures
byte_err(0x35,3,codeword);
byte_err(0x41,6,codeword);
byte_err(0x40,10,codeword);
byte_err(0x23,17,codeword);
byte_err(0x34,19,codeword);
byte_err(0x30,53,codeword);
byte_err(0x32,65,codeword);
printf("with some errors: \"%s\"\n",codeword);
// We need to indicate the position of the erasures.
// Eraseure positions are indexed (1 based) from the end of the message...
erasures[nerasures++]=ML-16;
erasures[nerasures++]=ML-54;
// Now decode -- encoded codeword size must be passed
[RS deCode:codeword:ML];
// check if syndrome is all zeros
if([RS checkSyndrome]!=0){
[RS correctErrorsErasures:codeword:ML:nerasures:erasures];
printf("Corrected codeword: \"%s\"\n",codeword);
}
// Release RSCode Encode Decode Object
[RS release];
[pool drain];
return 0;
}
SIKULI 為 GUI 自動化開了一道門
01/28/2010, 13:21 - Open Source
前天試用了一下來自台灣台中的 vgod 在MIT修業兩年的成果, SIKULI Project, 發覺這真的是像 vgod 自己在 Blog 說的是會改變 GUI 世界的東西啊. 這是可以將 GUI 的原本需要人一個一個click的用法, 變成 batch 的方式. 也就是說可以將多個 GUI 程式經由 SIKULI 串在一起, 完成一件事, 或者是可以將原本需要人用Mouse在電腦之前,一步一步的確認及回應, 現在可以將這些動作自動化了. 可以自動化對於常用電腦執行固定工作項目的人,是很重要的一個需求.讓電腦將經常需要重覆的工作自動化, 這樣人才有時間作別的事, Work Smart, do'nt work hard, 意思是說要聰明的工作, 而不要白費力氣的工作啊. 有了自動的 GUI script 正好補完了多年來 GUI 無法自動化的缺口.在Macintosh 有 Apple script可以作類似的工作, 不過前提是 GUI 程式要有支援 Scriptable 的介面, 和 Apple Script 連結起來, 才可以用 script 控制 GUI 的程式工作. 而在 UNIX 系統上(Linux/BSD/Solaris/AIX...都是), 可以用的 script 就更多了, Shell script, Perl, PHP, Python, Ruby, TCL/Tk, Expect等等, 各有不同的語法及用途, 不過有一個共通點, 就是只能用在文字模式, 或是自己所構成的 GUI 環境, 無法和別的 GUI 程式互動. 在 Microsoft 的作業系統上的 script 就更弱了, 來自80年代的 DOS batch file, 以少得可憐的指令, 及奇怪的用法, 一樣是工作文字模式下, 可以經由 VBScript 作出 GUI 及使用 OLE 和別的程式作有限度的互動, 雖然有人作出了 Autoit 和 AutoHotkey, 不過都需要使用文字程式碼寫成 script, 而這都需要一定的程式語言使用背景才可以完成,還是沒有 SIKULI 直接及簡單. 以前有一個作業系統叫 BeOS,可以用Cortex 在 GUI 中將各不同的影音來源輸入和輸出串在一起,一起工作,例如從介面錄音之後直接送到MP3 encoder壓縮後,再送到音效卡輸出,全部用GUI將線接在一起就可以,不過 BeOS 已經是昨日黃花,已經進入歷史了,現在有的只有一個相容的 Open source 計畫,叫作 Haiku。
SIKULI 使用的方法說起來也很簡單, 就是先將要做動作的圖象, 用 screen capture 給剪下來, 在執行 script 時進行比對, 若有一定程度的相似性(可在 script 中設定),就作 script 中指定的動作, 如 type 一段文數字,或是按一下 botton. 這樣子的作法是比較慢, 但好處是沒有作業系統相容的問題, 也沒有需要連結程式庫或預先作好的介面問題, 一切都和人在使用 GUI 介面時一樣, 用眼睛看, 選擇相對 icon, 作出對應的事件,像是按一次,或兩次, 或輸入資料等. 夠直接了吧!
我花了三分鐘就作了一個可以將 Windows 關機的 script.

簡單吧,在 SIKULI 的網頁上還有很多的例子。
最棒的是 SIKULI 是 Open source, 所以應該可以在任何電腦系統上,經過一定的修補後執行. SIKULI 使用 Jython, 所以要有 Java JDK/JRE 才可以執行.不過在 Windows 版的好像 save 就會 crash, 而 OS X 版的就不會. Linux 還在和 OpenCV Library 打架中. 在 Windows 版本上可以設定 screen capture 的時間 delay, 以免還沒有找到要按的按鍵就 timeout 了. 我是設成 3 秒, 好像比較可以符合慢慢的 Windows XP.
SIKULI 使用 Jython, 所以要有 Java JDK/JRE 才可以執行. 在作 screenshut 時要注意的是背景顏色, 會干擾圖象辦認的正確, 在使用時要小心. 也可以先用別的程式將圖象抓下來, 再放到 script 中, 可以節省時間. 我看到的是 SIKULI 使用 png 格式, 不知道 jpeg 和 gif 可不可以. 因為 SIKULI 現在還在 beta 版, 所以文件部份只有簡單的說明1, 希望未來會有較多較詳細的說明.
不過因為 SIKULI 是使用圖象辦認,所以看來 script 的可移動性會低一點,因為各作業系統,或每個人使用的圖象都可以自行改變,而改了當然就無法正確辦認出來了。
現在 vgod 用 SIKULI 為大家開了一扇門, 接下來要如何使用就看我們了吧! 像是測試軟體的可用性, 操作測試儀器, 或是經由多個程式共同完成一個工作等等. 去拿來試試吧, 並把你認為可以加強或不足的部份告訴 vgod , 或者自己從 source code 修改成你要的樣子.
SIKULI 網址 http://sikuli.org
vgod Blog http://blog.vgod.tw
vgod 在 twitter 上開了一個 SIKULI 的專推 sikuli@twitter
Arduino WebSwitch
12/14/2009, 17:13 - Open Source
加入了將設定寫至 Flash memory 及將 string 用 PANGMEM 放至 Flash memory 以縮小 RAM 的用量。因為測試用的 Arduino 只有 1024 byte RAM,所以要用時間換取空間,不然 1024 byte 很快就用光了。而且將原本一個 function 到底的程式,區分為多個共用 functions 以節省 Flash memory 的用量。看來效果還不錯,不過程式的可讀性變得很低。下一個來試試 Telnet 和 Finger,若拿到 ATMega328 就有 2K RAM 和 32K Flash memory 可以用,就可以將所有的 services 放在一起了。 這個程式很簡單,在 8 支 digital pin 上,連接電晶體當電子開關,控制 Relay 或 SSR,作為網路可控制110V/220V的 8 孔電源開關。可以由 Web browser 得知開關的狀態。預設的 IP address 是用 169.254.0.0/16 所以可以在一開始時用簡單 Crossover 線,接上PC Windows (設定為 DHCP)的方式設定好正確的 IP,也可以設定開關的 default 狀態。
/*
This program is wor Arduino Ethernet Shield with W5100 ethernet chip,
As a 8 digital pins control in web page
Version : 1.0
Programmer : Tasuka Hsu, Dec 1 2009
*/
// Library import
#include <Ethernet2.h>
#include <Print.h>
#include <Server.h>
#include <Client.h>
#include <EEPROM.h>
#include <avr/pgmspace.h>
// Const define
#define LENGTH 50 // Message length
#define PINS 8 // Digital pins 1 to 8
#define EEPROM_START_ADDRESS 0
#define EEPROM_MAC EEPROM_START_ADDRESS+10
#define EEPROM_IP EEPROM_MAC+6
#define EEPROM_SUBNET EEPROM_IP+4
#define EEPROM_GATEWAY EEPROM_SUBNET+4
#define EEPROM_PORT EEPROM_GATEWAY+4
#define EEPROM_REFRESH EEPROM_PORT+2
#define EEPROM_SW EEPROM_REFRESH+2
#define EEPROM_RESERVED EEPROM_SW+8
// MAC Address
byte MAC[]={0x80,0x0c,0x01,0x01,0xef,0xfe};
byte Default IP Address setting
byte IP[]={169,254,1,1};
byte GATEWAY[]={0,0,0,0};
byte SUBNET[]={255,255,0,0};
//byte IP[]={172,16,7,250};
//byte GATEWAY[]={172,16,7,254};
//byte SUBNET[]={255,255,255,248};
byte SW[PINS]={0,0,0,0,0,0,0,0}; /* Switch defult state config */
unsigned int PORT=80; // HTTP port
unsigned int REFRESH=120; // HTTP refresh timer
// Keep Strings in Flash Memory not load into RAM for RAM space save
static char TITLE_S[] PROGMEM = "Adruino Digital Pins Control";
static char ANNOUNCE[] PROGMEM = "Tasuka Lab";
static char FOOTER0[] PROGMEM = "Open source of hardware and software for Arduino";
static char FOOTER1[] PROGMEM = "Program By Tasuka Hsu";
static char ARDUINO_WEB[] PROGMEM = "http://www.arduino.cc";
static char HTML_HEADER0[] PROGMEM = "HTTP/1.1 200 OK";
static char HTML_HEADER1[] PROGMEM = "Content-Type: text/html; charset=utf-8";
static char HTML[] PROGMEM = "<html>";
static char HTML_[] PROGMEM = "</html>";
static char TITLE[] PROGMEM = "<title>";
static char TITLE_[] PROGMEM = "</title>";
static char HEAD[] PROGMEM = "<head>";
static char HEAD_[] PROGMEM = "</head>";
static char CENTER[] PROGMEM = "<center>";
static char CENTER_[] PROGMEM = "</center>";
static char BODY[] PROGMEM = "<body>";
static char BODY_[] PROGMEM = "</body>";
static char INPUT_TEXT[] PROGMEM = "<input type=\"text\" name=\"";
static char INPUT_TEXT_[] PROGMEM = "\" value=\"";
static char INPUT_TEXT__[] PROGMEM = "\" size=\"";
static char INPUT_TEXT___[] PROGMEM = "\">";
static char INPUT_RADIO[] PROGMEM = "<input type=\"radio\" name=\"";
static char META[] PROGMEM = "<meta http-equiv=\"refresh\" content=\"";
static char META_[] PROGMEM = ";url=/\">";
static char SUBMIT[] PROGMEM = "<input type=\"submit\" value=\"Send\">";
static char CLEAR_BUF_CHKBX[] PROGMEM = "Clear Config<input type=\"checkbox\" name=\"cl0\">";
static char CHKBOX[] PROGMEM = "<input type=\"radio\" name=\"";
static char URL_BTN_RETURN[] PROGMEM ="<a href=\"/\"><input type=\"button\" value=\"Return\"></a>";
static char URL_BTN_BACK[] PROGMEM = "<a href=\"/?g=1\"><input type=\"button\" value=\"Back\"></a>";
static char URL_BTN_CONFIG[] PROGMEM ="<a href=\"/?g=1\"><input type=\"button\" value=\"Config\"></a>";
static char FORM[] PROGMEM = "<form method=\"GET\" action=\"/\">";
static char FORM_[] PROGMEM = "</form>";
static char DIGITAL_TITLE[] PROGMEM = "<tr><td>Digital Pin</td><td>On</td><td>Off</td></tr>";
static char TABLE_BORDER[] PROGMEM = "<table border=\"1\" align=\"center\">";
static char TABLE_NO_BORDER[] PROGMEM="<table border=\"0\" align=\"center\">";
static char TABLE_[] PROGMEM = "</table>";
static char MAC_CONFIG[] PROGMEM = "<a href=\"/?g=2\">Config MAC Address</a>";
static char IP_CONFIG[] PROGMEM = "<a href=\"/?g=3\">Config IP Address</a>";
static char SUBNET_CONFIG[] PROGMEM = "<a href=\"/?g=4\">Config Subnet Mask</a>";
static char GATEWAY_CONFIG[] PROGMEM ="<a href=\"/?g=5\">Config Gateway Address</a>";
static char PORT_CONFIG[] PROGMEM = "<a href=\"/?g=6\">Config TCP Port</a>";
static char REFRESH_CONFIG[] PROGMEM ="<a href=\"/?g=7\">Config HTML Refresh Time</a>";
static char SW_CONFIG[] PROGMEM = "<a href=\"/?g=8\">Config SW Default State</a>";
static char MAC_TITLE[] PROGMEM = "<tr><td>MAC Address</td><td>";
static char IP_TITLE[] PROGMEM = "<tr><td>IP Address</td><td>";
static char SUBNET_TITLE[] PROGMEM = "<tr><td>Subnet Mask</td><td>";
static char GATEWAY_TITLE[] PROGMEM = "<tr><td>Gateway</td><td>";
static char PORT_TITLE[] PROGMEM = "<tr><td>TCP Port</td><td>";
static char REFRESH_TITLE[] PROGMEM = "<tr><td>HTML Refresh Time</td><td>";
static char SW_TITLE[] PROGMEM = "<tr><td>Switch Default State</td><td>";
static char TD_TR_[] PROGMEM = "</td></tr>";
static char TD_TR_BR[] PROGMEM = "</td></tr><br><tr><td>";
static char ON_OFF[] PROGMEM = "<tr><td></td><td>On/Off</td></tr>";
static char CHECKED[] PROGMEM = "\" checked=\"checked";
static char SPACE[] PROGMEM = " ";
// The string address pointer
PROGMEM const char *string_table[]={
TITLE_S, //0
ANNOUNCE,
FOOTER0,
FOOTER1,
ARDUINO_WEB,
HTML_HEADER0, //5
HTML_HEADER1,
HTML,
HTML_,
TITLE,
TITLE_, //10
HEAD,
HEAD_,
CENTER,
CENTER_,
META, //15
BODY,
BODY_,
INPUT_TEXT,
INPUT_TEXT_,
INPUT_TEXT__, //20
INPUT_TEXT___,
SUBMIT,
CLEAR_BUF_CHKBX,
URL_BTN_RETURN,
URL_BTN_BACK, //25
URL_BTN_CONFIG,
TABLE_,
FORM,
META_,
DIGITAL_TITLE, //30
TABLE_BORDER,
MAC_CONFIG,
IP_CONFIG,
SUBNET_CONFIG,
GATEWAY_CONFIG, // 35
PORT_CONFIG,
REFRESH_CONFIG,
TABLE_NO_BORDER,
MAC_TITLE,
IP_TITLE, //40
SUBNET_TITLE,
GATEWAY_TITLE,
PORT_TITLE,
REFRESH_TITLE,
INPUT_RADIO, //45
FORM_,
TD_TR_,
SW_CONFIG,
SW_TITLE,
CHKBOX, //50
TD_TR_BR,
ON_OFF,
CHECKED,
SPACE
};
// RAM buffer for strings move from flash memory
char buffer[70];
// CGI GET messages buffer
char MESSAGE[LENGTH+1];
byte page=0;
boolean bootUp=true;
// HTTP Server setting
//Server server=Server(PORT);
// Load string's content from Flash memory by index of pointer to RAM
void get2RAM(byte k)
{
strcpy_P(buffer,(char *)pgm_read_word(&(string_table[k])));
}
void ReadWriteConfig()
{
byte i=0;
get2RAM(1);
// Write default data to EEPROM
if((EEPROM.read(EEPROM_START_ADDRESS)!=buffer[0])&&(EEPROM.read(EEPROM_START_ADDRESS+1)!=buffer[1])){
for(i=0;i<10;i++){
EEPROM.write(EEPROM_START_ADDRESS+i,buffer);
if(i<PINS){
EEPROM.write(EEPROM_SW+i,LOW);
SW=0;
if(i<6){
EEPROM.write(EEPROM_MAC+i,MAC);
if(i<4){
EEPROM.write(EEPROM_IP+i,IP);
EEPROM.write(EEPROM_GATEWAY+i,GATEWAY);
EEPROM.write(EEPROM_SUBNET+i,SUBNET);
}
}
}
}
EEPROM.write(EEPROM_PORT,byte((PORT&0xff00)/256));
EEPROM.write(EEPROM_PORT+1,byte(PORT&0x00ff));
EEPROM.write(EEPROM_REFRESH,byte((REFRESH&0xff00)/256));
EEPROM.write(EEPROM_REFRESH+1,byte(REFRESH&0x00ff));
}else{
// Read config data from EEPROM
for(i=0;i<PINS;i++){
SW=EEPROM.read(EEPROM_SW+i);
if(i<6){
MAC=EEPROM.read(EEPROM_MAC+i);
if(i<4){
IP=EEPROM.read(EEPROM_IP+i);
GATEWAY=EEPROM.read(EEPROM_GATEWAY+i);
SUBNET=EEPROM.read(EEPROM_SUBNET+i);
}
}
}
PORT=(int(EEPROM.read(EEPROM_PORT))*256)+int(EEPROM.read(EEPROM_PORT+1));
REFRESH=(int(EEPROM.read(EEPROM_REFRESH))*256)+int(EEPROM.read(EEPROM_REFRESH+1));
}
}
void char2Hex(byte m)
{
byte j=0;
for(byte i=0;i<2;i++){
if(i==0){
j=(m&0xf0)/16;
}else{
j=m&0x0f;
}
if(j>=0&&j<=9){
buffer=char(int(j)+'0');
}else{
buffer=char(int(j)+'A'-10);
}
}
buffer[2]='\0';
}
byte getIP(byte i,byte t)
{
byte j=MESSAGE[i+2]-'0';
byte k=4;
if(j>=0&&j<4){
byte l=0;
while((MESSAGE[i+k]!='&')&&(MESSAGE[i+k]!=' ')&&(MESSAGE[i+k]!='\n')&&(MESSAGE[i+k]!='\r')&&(MESSAGE[i+k]!='\0')){
l=l*10+byte(MESSAGE[i+k]-'0');
k++;
}
switch(t){
case 1:
IP[j]=l;
EEPROM.write(EEPROM_IP+j,l);
break;
case 2:
SUBNET[j]=l;
EEPROM.write(EEPROM_SUBNET+j,l);
break;
case 3:
GATEWAY[j]=l;
EEPROM.write(EEPROM_GATEWAY+j,l);
break;
}
}
return(k);
}
byte getDigit(byte i,byte t)
{
byte k=4;
unsigned int l=0;
while((MESSAGE[i+k]!='&')&&(MESSAGE[i+k]!=' ')&&(MESSAGE[i+k]!='\n')&&(MESSAGE[i+k]!='\r')&&(MESSAGE[i+k]!='\0')){
l=l*10+byte(MESSAGE[i+k]-'0');
k++;
}
switch(t){
case 1:
PORT=l;
EEPROM.write(EEPROM_PORT,byte((PORT&0xff00)/256));
EEPROM.write(EEPROM_PORT+1,byte(PORT&0x00ff));
break;
case 2:
REFRESH=l;
EEPROM.write(EEPROM_REFRESH,byte((REFRESH&0xff00)/256));
EEPROM.write(EEPROM_REFRESH+1,byte(REFRESH&0x00ff));
break;
}
return(k);
}
void parseCGI()
{
byte i=0;
byte flag=false;
// Send to Digital pins from parse HTTP send message
while(MESSAGE!='\0'){
// Port Status
if((MESSAGE=='p'||MESSAGE=='P')&&(MESSAGE[i+2]=='=')){
digitalWrite(int(MESSAGE[i+1])-'0',int(MESSAGE[i+3])-'0');
i+=3;
}
// Page
if((MESSAGE=='g'||MESSAGE=='G')&&(MESSAGE[i+1]=='=')){
page=MESSAGE[i+2]-'0';
i+=2;
}
// Clear EEPROM to zero
if((MESSAGE=='c'||MESSAGE=='C')&&(MESSAGE[i+1]=='l'||MESSAGE[i+1]=='L')&&(MESSAGE[i+2]=='0')&&(MESSAGE[i+3]=='=')){
for(int j=0;j<512;j++){
EEPROM.write(EEPROM_START_ADDRESS+j,0);
}
i+=6;
}
// MAC Address Config and Write MAC to EEPROM
if((MESSAGE=='m'||MESSAGE=='M')&&(MESSAGE[i+1]=='a'||MESSAGE[i+1]=='A')&&(MESSAGE[i+3]=='=')){
byte j=MESSAGE[i+2]-'0';
if(j>=0&&j<6){
for(byte l=0;l<2;l++){
byte k=MESSAGE[i+4+l];
// Change to upper case
if(k>'Z'){
k=k-'a'+'A';
}
if(k<='9'&&k>='0'){
switch(l){
case 0:
MAC[j]=byte(int(k-'0')*16);
break;
case 1:
MAC[j]+=byte(int(k-'0'));
break;
}
}else{
switch(l){
case 0:
MAC[j]=byte(int(k-'A'+10)*16);
break;
case 1:
MAC[j]+=byte(int(k-'A'+10));
break;
}
}
}
EEPROM.write(EEPROM_MAC+j,MAC[j]);
}
i+=5;
}
// IP Address Config and Write to EEPROM
if((MESSAGE=='i'||MESSAGE=='I')&&(MESSAGE[i+1]=='p'||MESSAGE[i+1]=='P')&&(MESSAGE[i+3]=='=')){
i+=getIP(i,1);
}
// Subnet Address Config and Write to EEPROM
if((MESSAGE=='s'||MESSAGE=='S')&&(MESSAGE[i+1]=='b'||MESSAGE[i+1]=='B')&&(MESSAGE[i+3]=='=')){
i+=getIP(i,2);
}
// Gateway Address Config and Write to EEPROM
if((MESSAGE=='g'||MESSAGE=='G')&&(MESSAGE[i+1]=='w'||MESSAGE[i+1]=='W')&&(MESSAGE[i+3]=='=')){
i+=getIP(i,3);
}
// Port Config and Write to EEPROM
if((MESSAGE=='p'||MESSAGE=='P')&&(MESSAGE[i+1]=='r'||MESSAGE[i+1]=='R')&&(MESSAGE[i+2]=='0')&&(MESSAGE[i+3]=='=')){
i+=getDigit(i,1);
}
// Refresh Time Config and Write to EEPROM
if((MESSAGE=='r'||MESSAGE=='R')&&(MESSAGE[i+1]=='f'||MESSAGE[i+1]=='F')&&(MESSAGE[i+2]=='0')&&(MESSAGE[i+3]=='=')){
i+=getDigit(i,2);
}
// Switch default state Config and Write to EEPROM
if((MESSAGE=='s'||MESSAGE=='S')&&(MESSAGE[i+1]=='w'||MESSAGE[i+1]=='W')&&(MESSAGE[i+3]=='=')){
byte j=MESSAGE[i+2]-'0';
SW[j]=byte(MESSAGE[i+4]-'0');
EEPROM.write(EEPROM_SW+j,SW[j]);
i+=5;
}
i++;
}
}
void setup()
{
// Read/Write config from/to EEPROM
ReadWriteConfig();
// Initial digital pin setting to EEPROM store setting
for(byte i=0;i<PINS;i++){
pinMode(i,OUTPUT);
digitalWrite(i,SW);
}
}
void loop()
{
Server server=Server(PORT);
if(bootUp){
// Initial Ethernet MAC and IP setting
Ethernet.begin(MAC,IP,GATEWAY,SUBNET);
// Start server listen
server.begin();
bootUp=false;
}
/* Initial client */
Client client=server.available();
if(client) {
boolean current_line_is_blank=true,flag=false;
char c='\0';
byte i=0;
// If connected
while(client.connected()){
if(client.available()){
/* Clear MESSAGE */
for(i=0;i<LENGTH;i++){
MESSAGE='\0';
}
flag=false;
i=0;
// Read from HTTP GET input information
while((c=client.read())!='\n' && i<=LENGTH){
if(c=='?'){
flag=true;
}
if(c==' '||c=='\n'||c=='\0'){
flag=false;
}
if(flag){
MESSAGE[i++]=c;
}
}
MESSAGE='\0';
page=0;
parseCGI();
if(current_line_is_blank){
// Send HTTP header
get2RAM(5);
client.println(buffer);
//client.println("HTTP/1.1 200 OK");
get2RAM(6);
client.println(buffer);
//client.println("Content-Type: text/html; charset=utf-8");
client.println();
// Send HTML
get2RAM(7);
client.println(buffer);
//client.println("<html>");
get2RAM(9);
client.print(buffer);
//client.print("<title>");
get2RAM(0);
client.print(buffer);
//client.print(TITLE);
get2RAM(10);
client.println(buffer);
//client.println("</title>");
get2RAM(11);
//client.print("<head>");
client.print(buffer);
get2RAM(13);
client.print(buffer);
//client.print("<center>");
client.print("<h1>");
get2RAM(0);
client.print(buffer);
//client.print(TITLE);
client.print("</h1>");
get2RAM(14);
client.print(buffer);
//client.println("</center>");
get2RAM(15);
client.print(buffer);
//client.print("<meta http-equiv=\"refresh\" content=\"");
if(page==0){
client.print(REFRESH);
}else{
client.print(3600);
}
get2RAM(29);
client.print(buffer);
//client.println(";url=/\">");
get2RAM(12);
client.println(buffer);
//client.println("</head>");
get2RAM(16);
client.print(buffer);
//client.println("<body>");
client.println("<hr>");
get2RAM(28);
client.print(buffer);
//client.print("<form method=\"");
//client.print("GET");
//client.print("\"");
//client.println(" action=\"/\">");
if(page==0){
// Read data from digital pin
get2RAM(31);
client.print(buffer);
/*
client.print("<table border=\"");
client.print(1);
client.print("\"");
client.print(" ");
client.print("align=\"");
client.print("center");
client.print("\"");
client.println(">");
*/
get2RAM(30);
client.print(buffer);
/*
client.print("<tr>");
client.print("<td>");
client.print("Digital");
client.print(" ");
client.print("Pin");
client.print("</td>");
client.print("<td>");
client.print("On");
client.print("</td>");
client.print("<td>");
client.print("Off");
client.print("</td>");
client.println("</tr>");
*/
for(i=0;i<PINS;i++){
client.print("<tr><td>SW ");
client.print(int(i));
client.println("</td><td>");
/* Display pins status */
if(digitalRead(i)==HIGH){
get2RAM(45);
client.print(buffer);
client.print("p");
client.print(int(i));
get2RAM(53);
client.print(buffer);
//client.print("\" checked=\"checked");
client.print(1);
get2RAM(21);
client.print(buffer);
/*
client.print("<input type=radio");
client.print(" ");
client.print("name=\"");
client.print("p");
client.print(int(i));
client.print("\"");
client.print(" ");
client.print("checked");
client.print(" ");
client.print("value=\"");
client.print(1);
client.print("\">");
*/
client.println("</td>");
client.print("<td>");
get2RAM(45);
client.print(buffer);
client.print("p");
client.print(int(i));
get2RAM(19);
client.print(buffer);
client.print(0);
get2RAM(21);
client.print(buffer);
/*
client.print("<input type=radio");
client.print(" ");
client.print("name=\"");
client.print("p");
client.print(int(i));
client.print("\"");
client.print(" ");
client.print("value=\"");
client.print(0);
client.println("\">");
*/
}else{
get2RAM(45);
client.print(buffer);
client.print("p");
client.print(int(i));
get2RAM(19);
client.print(buffer);
client.print(1);
get2RAM(21);
client.print(buffer);
/*
client.print("<input type=radio");
client.print(" ");
client.print("value=\"");
client.print(1);
client.print("\"");
client.print(" ");
client.print("name=\"");
client.print("p");
client.print(int(i));
client.print("\">");
*/
client.println("</td>");
client.print("<td>");
get2RAM(45);
client.print(buffer);
client.print("p");
client.print(int(i));
get2RAM(53);
client.print(buffer);
//client.print("\" checked=\"checked");
get2RAM(19);
client.print(buffer);
client.print(0);
get2RAM(21);
client.print(buffer);
/*
client.print("<input type=radio");
client.print(" ");
client.print("checked");
client.print(" ");
client.print("value=\"");
client.print(0);
client.print("\"");
client.print(" ");
client.print("name=\"");
client.print("p");
client.print(int(i));
client.println("\">");
*/
}
get2RAM(47);
client.print(buffer);
//client.println("</td></tr>");
}
get2RAM(27);
client.print(buffer);
//client.print("</table>");
}
get2RAM(13);
client.print(buffer);
//client.print("<center>");
if(page==1){
get2RAM(32);
client.print(buffer);
/*
client.print("<a href=\"/?g=");
client.print(2);
client.print("\"");
client.print(">");
client.print("Config");
client.print(" ");
client.print("MAC Address");
client.print("</a>");
*/
client.println("<br>");
get2RAM(33);
client.print(buffer);
/*
client.print("<a href=\"/?g=");
client.print(3);
client.print("\"");
client.print(">");
client.print("Config");
client.print(" ");
client.print("IP Address");
client.print("</a>");
*/
client.println("<br>");
get2RAM(34);
client.print(buffer);
/*
client.print("<a href=\"/?g=");
client.print(4);
client.print("\"");
client.print(">");
client.print("Config");
client.print(" ");
client.print("Subnet Mask");
client.print("</a>");
*/
client.println("<br>");
get2RAM(35);
client.print(buffer);
/*
client.print("<a href=\"/?g=");
client.print(5);
client.print("\"");
client.print(">");
client.print("Config");
client.print(" ");
client.print("Gateway Address");
client.print("</a>");
*/
client.println("<br>");
get2RAM(36);
client.print(buffer);
/*
client.print("<a href=\"/?g=");
client.print(6);
client.print("\"");
client.print(">");
client.print("Config");
client.print(" ");
client.print("TCP Port");
client.print("</a>");
*/
client.println("<br>");
get2RAM(37);
client.print(buffer);
/*
client.print("<a href=\"/?g=");
client.print(7);
client.print("\"");
client.print(">");
client.print("Config");
client.print(" ");
client.print("HTML Refresh Time");
client.print("</a>");
*/
client.println("<br>");
get2RAM(48);
client.print(buffer);
client.println("<br>");
}
if(page>=2){
get2RAM(38);
client.print(buffer);
/*
client.print("<table border=\"");
client.print(0);
client.print("\"");
client.print(" ");
client.print("align=\"");
client.print("center");
client.print("\"");
client.print(">");
*/
if(page==2){
get2RAM(39);
client.print(buffer);
/*
client.println("<tr>");
client.print("<td>");
client.print("MAC Address");
client.println("</td>");
client.print("<td>");
*/
for(i=0;i<6;i++){
if(i>0&&i<6){
client.print(":");
}
get2RAM(18);
client.print(buffer);
client.print("ma");
client.print(int(i));
get2RAM(19);
client.print(buffer);
char2Hex(MAC);
client.print(buffer);
get2RAM(20);
client.print(buffer);
client.print(2);
get2RAM(21);
client.print(buffer);
}
client.println("</td>");
}
if(page==3){
get2RAM(40);
client.print(buffer);
/*
client.println("<tr>");
client.print("<td>");
client.print("IP Address");
client.println("</td>");
client.println("<td>");
*/
for(i=0;i<4;i++){
if(i>0&&i<4){
client.print(".");
}
get2RAM(18);
client.print(buffer);
client.print("ip");
client.print(int(i));
get2RAM(20);
client.print(buffer);
client.print(3);
get2RAM(19);
client.print(buffer);
client.print(int(IP));
get2RAM(21);
client.print(buffer);
}
get2RAM(47);
client.print(buffer);
//client.println("</td></tr>");
}
if(page==4){
get2RAM(41);
client.print(buffer);
/*
client.println("<tr>");
client.print("<td>");
client.print("Subnet Mask");
client.println("</td>");
client.println("<td>");
*/
for(i=0;i<4;i++){
if(i>0&&i<4){
client.print(".");
}
get2RAM(18);
client.print(buffer);
client.print("sb");
client.print(int(i));
get2RAM(20);
client.print(buffer);
client.print(3);
get2RAM(19);
client.print(buffer);
client.print(int(SUBNET));
get2RAM(21);
client.print(buffer);
}
get2RAM(47);
client.print(buffer);
//client.println("</td></tr>");
}
if(page==5){
get2RAM(42);
client.print(buffer);
/*
client.println("<tr>");
client.println("<td>");
client.print("Gateway");
client.println("</td>");
client.print("<td>");
*/
for(i=0;i<4;i++){
if(i>0&&i<4){
client.print(".");
}
get2RAM(18);
client.print(buffer);
client.print("gw");
client.print(int(i));
get2RAM(20);
client.print(buffer);
client.print(3);
get2RAM(19);
client.print(buffer);
client.print(int(GATEWAY));
get2RAM(21);
client.print(buffer);
}
get2RAM(47);
client.print(buffer);
//client.println("</td></tr>");
}
if(page==6){
get2RAM(43);
client.print(buffer);
/*
client.println("<tr>");
client.print("<td>");
client.print("TCP Port");
client.println("</td>");
client.println("<td>");
*/
get2RAM(18);
client.print(buffer);
client.print("pr");
client.print(0);
get2RAM(20);
client.print(buffer);
client.print(5);
get2RAM(19);
client.print(buffer);
client.print((unsigned int)int(PORT));
get2RAM(21);
client.print(buffer);
get2RAM(47);
client.print(buffer);
//client.println("</td></tr>");
}
if(page==7){
//client.println("<td>");
get2RAM(44);
client.print(buffer);
get2RAM(18);
client.print(buffer);
client.print("rf");
client.print(0);
get2RAM(20);
client.print(buffer);
client.print(3);
get2RAM(19);
client.print(buffer);
client.print((unsigned int)int(REFRESH));
get2RAM(21);
client.print(buffer);
get2RAM(47);
client.print(buffer);
//client.println("</td></tr>");
}
if(page==8){
get2RAM(49);
client.print(buffer);
get2RAM(51);
client.print(buffer);
//client.print("</td></tr><br><tr><td>");
get2RAM(38);
client.print(buffer);
get2RAM(52);
client.print(buffer);
//client.println("<tr><td></td><td>On/Off</td></tr>");
for(i=0;i<PINS;i++){
client.print("<tr><td>SW");
client.print(int(i));
client.print("</td><td>");
get2RAM(45);
client.print(buffer);
//client.print("<input type=\"radio\" name=\"sw");
client.print("sw");
client.print(int(i));
get2RAM(19);
client.print(buffer);
//client.print("\" value=\"");
client.print(1);
if(SW==1){
get2RAM(53);
client.print(buffer);
//client.print("\" checked=\"checked");
}
get2RAM(21);
client.print(buffer);
get2RAM(45);
client.print(buffer);
//client.print("<input type=\"radio\" name=\"sw");
client.print("sw");
client.print(int(i));
get2RAM(19);
client.print(buffer);
//client.print("\" value=\"");
client.print(0);
if(SW==0){
get2RAM(53);
client.print(buffer);
//client.print("\" checked=\"checked");
}
get2RAM(21);
client.print(buffer);
get2RAM(47);
client.print(buffer);
//client.println("</td></tr>");
}
get2RAM(27);
client.print(buffer);
//client.print("</table>");
get2RAM(47);
client.print(buffer);
//client.print("</td></tr>");
get2RAM(47);
client.print(buffer);
//client.println("</td></tr>");
}
get2RAM(27);
client.print(buffer);
//client.println("</table>");
client.println("<br>");
}
get2RAM(14);
client.print(buffer);
//client.println("</center>");
if(page>=2){
get2RAM(13);
client.print(buffer);
//client.println("<center>");
get2RAM(23);
client.print(buffer);
get2RAM(14);
client.print(buffer);
//client.println("</center>");
client.println("<br>");
}
if(page!=1){
get2RAM(13);
client.print(buffer);
//client.println("<center>");
get2RAM(22);
client.print(buffer);
get2RAM(14);
client.print(buffer);
//client.println("</center>");
}
get2RAM(46);
client.print(buffer);
//client.println("</form>");
client.println("<br>");
client.print("<hr>");
get2RAM(13);
client.print(buffer);
//client.print("<center>");
if(page==0){
get2RAM(26);
client.print(buffer);
}
if(page>=2){
get2RAM(25);
client.print(buffer);
}
if(page!=0){
get2RAM(24);
client.print(buffer);
}
get2RAM(14);
client.print(buffer);
//client.print("</center>");
client.println("<br>");
/*
// Debug received message
client.print("Message=");
client.println(MESSAGE);
for(i=0;i<16;i++){
client.print(int(EEPROM.read(EEPROM_START_ADDRESS+i)));
client.print(" ");
}
client.print("Page ");
client.println(int(page));
// Debug message end
*/
// HTML tail
client.println("<h6>");
get2RAM(2);
client.print(buffer);
client.print("<br>");
//client.println("Open source of hardware and software for Arduino";
client.print("<a href=");
get2RAM(4);
client.print(buffer);
//client.print("http://www.arduino.cc");
client.print(">");
get2RAM(4);
client.print(buffer);
//client.print("http://www.arduino.cc");
client.print("</a>");
client.print("<br>");
get2RAM(3);
client.println(buffer);
client.println("<br>");
client.println("</h6>");
get2RAM(17);
client.println(buffer);
//client.println("</body>");
get2RAM(8);
client.println(buffer);
//client.println("</html>");
break;
}
if(c=='\n'){
current_line_is_blank=false;
}
}
}
delay(1);
client.stop();
}
}
Arduino Ethernet Shield
12/02/2009, 17:15 - Open Source
花了一點時間,用了一下Arduino 這個小東西,Open source 的硬體和軟體。順便作了一個可以經由網路控制的數位腳,及SSR當作電源開關。這個程式加上了 Arduino Ethernet Shield 可以用 Arduino Ethernet Library 也可以換成 Ethernet2 Library,用 Ethernet2 空間會比較省。下次再配合 Arduino SD shield 看看吧!作起來比 Microship 的 PIC 簡單,程式工具不用錢,可以在Windows/Mac OS X/Linux 下寫程式,不必被限制一定要用Windows。不必買燒錄工具,用 USB 就可以寫入資料。不過在燒入資料時,digital pin 1 和 2 不可以接東西。目前 MAC address 和 IP 是固定的,有空再試試 DHCP library。
/*
This program is wor Arduino Ethernet Shield with W5100 ethernet chip,
As a 8 digital pins control in web page
Programmer : Tasuka Hsu, Dec 1 2009
*/
/* Library import */
#include <Ethernet2.h>
#include <Print.h>
#include <Server.h>
#include <Client.h>
/* Const define */
#define LENGTH 42 /* Message length */
#define PINS 8 /* Digital pins 1 to 8 */
#define PORT 80 /* HTTP port */
#define REFRESH 10 /* HTTP refresh timer */
/* MAC Address */
byte MAC[]={0x00,0x0c,0x01,0x01,0xef,0xff};
/* IP Address setting */
byte IP[]={172,16,7,251};
byte GATEWAY[]={172.16,7,254};
byte SUBNET[]={255,255,255,248};
/* HTTP Server setting */
Server server=Server(PORT);
char TITLE[]="Adruino Digital Pins Control";
char MESSAGE[LENGTH+1];
void setup()
{
/* Initial Ethernet MAC and IP setting */
Ethernet.begin(MAC,IP,GATEWAY,SUBNET);
/* Initial digital pin setting to default 0 */
for(int i=0;i<PINS;i++){
pinMode(i,OUTPUT);
digitalWrite(i,0);
}
/* Start server listen */
server.begin();
}
void loop()
{
/* Initial client */
Client client=server.available();
if(client) {
boolean current_line_is_blank=true,flag=false;
char c='\0';
int i=0;
/* If connected */
while(client.connected()){
if(client.available()){
/* Clear MESSAGE */
for(i=0;i<LENGTH;i++){
MESSAGE='\0';
}
flag=false;
i=0;
/* Read from HTTP GET input information */
while((c=client.read())!='\n' && i<=LENGTH){
if(c=='?'){
flag=true;
}
if(c==' '||c=='\n'||c=='\0'){
flag=false;
}
if(flag){
MESSAGE[i++]=c;
}
}
MESSAGE='\0';
i=0;
flag=false;
/* Send to Digital pins from parse HTTP send message */
while(MESSAGE!='\0'){
if((MESSAGE=='p'||MESSAGE=='P')&&(MESSAGE[i+2]=='=')){
digitalWrite(int(MESSAGE[i+1])-0x30,int(MESSAGE[i+3])-0x30);
i+=3;
}
i++;
}
if(current_line_is_blank){
/* Send HTTP header */
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html; charset=utf-8");
client.println();
/* Send HTML */
client.print("<html>\n<title>");
client.print(TITLE);
client.print("</title>\n<head>\n<center><h1>");
client.print(TITLE);
client.print("</h1></center>\n");
client.print("<meta http-equiv=\"refresh\" content=\"");
client.print(REFRESH);
client.print(";url=/\">\n</head>\n<body>\n");
client.print("<hr>\n<form method=\"GET\" action=\"/\">\n");
/* Read data from digital pin */
client.print("<table border=\"1\">\n");
client.print("<tr><td>Digital Pin</td><td>On</td><td>Off</td></tr>\n");
for(i=0;i<8;i++){
client.print("\n<tr><td>Pin ");
client.print(i);
client.print("</td>\n<td>");
/* Display pins status */
if(digitalRead(i)==1){
client.print("<input type=radio checked value=1 name=\"p");
client.print(i);
client.print("\"></td>\n");
client.print("<td><input type=radio value=0 name=\"p");
client.print(i);
client.print("\">\n");
}else{
client.print("<input type=radio value=1 name=\"p");
client.print(i);
client.print("\"></td>\n");
client.print("<td><input type=radio checked value=0 name=\"p");
client.print(i);
client.print("\">\n");
}
client.print("</td></tr>\n");
}
client.print("</table>\n");
client.print("<br><input type=submit value=\"Send\"></form><br>\n");
/* Debug received message */
// client.print("Message=");
// client.println(MESSAGE);
/* HTML tail */
client.print("<h6>\nOpen source of hardware and software for Arduino\n<br>\n");
client.print("<a href=http://www.arduino.cc>http://www.arduino.cc</a></h6>\n");
client.print("</body>\n</html>\n");
break;
}
if(c=='\n'){
current_line_is_blank=false;
}
}
}
delay(1);
client.stop();
}
}















