2017年7月29日 星期六

A pattern for state machine


State machine是很常見的應用/Pattern,這章節會根據下面的圖來實作State machine pattern


enum state {
 STATE_INITIAL = 0,
 STATE_1,
 STATE_2,
 STATE_3,
 STATE_4,
};

enum event {
 E1 = 1,
 E2,
 E3,
 E4,
};
先定義State Machine狀態與Event



struct instance_data {
 enum event evt;
 int data;
};

struct instance {
 enum state cur_state;
 struct instance_data data;
};
定義一個struct來儲存"現在狀態",Event與data



typedef enum state state_func_t(struct instance_data *data);

state_func_t* const state_table[] = {
 [STATE_INITIAL] = in_init,
 [STATE_1] = in_state_1,
 [STATE_2] = in_state_2,
 [STATE_3] = in_state_3,
 [STATE_4] = in_state_4,
};

void run_state(struct instance *inst)
{
 inst->cur_state = state_table[inst->cur_state](&(inst->data));
};

建立一個Table,將每一個state對應的function填入,run_state()會根據目前的State處理該event/data,並回傳下一個狀態



enum state in_state_1(struct instance_data *data)
{
 printf("%s(#%d): got EVT:%d\n", __FUNCTION__, __LINE__, data->evt);
 switch (data->evt) {
 case E1:
  printf("change to S2\n");
  return do_s2();
 case E2:
  printf("change to S3\n");
  return do_s3();
 default:
  printf("keep the same STATE && do nothing\n");
  return STATE_1;
 }
}

enum state in_state_2(struct instance_data *data)
{
 printf("%s(#%d): got EVT:%d\n", __FUNCTION__, __LINE__, data->evt);
 switch (data->evt) {
 case E3:
  printf("change to S3\n");
  return do_s3();
 default:
  printf("keep the same STATE && do s2 again\n");
  return do_s2(); // do s2 again
 }
}

enum state in_state_3(struct instance_data *data)
{
 printf("%s(#%d): got EVT:%d\n", __FUNCTION__, __LINE__, data->evt);
 switch (data->evt) {
 case E2:
  printf("change to S4\n");
  return do_s4();
 default:
  printf("keep the same STATE && do nothing\n");
  return STATE_3;
 }
}

enum state in_state_4(struct instance_data *data)
{
 printf("%s(#%d): got EVT:%d\n", __FUNCTION__, __LINE__, data->evt);
 switch (data->evt) {
 case E1:
  printf("change to S2\n");
  return do_s2();
 case E3:
  printf("change to S1\n");
  return do_s1();
 default:
  printf("keep the same STATE && do again\n");
  return do_s4();
 }
}
定義每一個狀態中的行為



enum state do_s1(void)
{
 printf("%s(#%d)\n", __FUNCTION__, __LINE__);
 return STATE_1;
}

enum state do_s2(void)
{
 printf("%s(#%d)\n", __FUNCTION__, __LINE__);
 return STATE_2;
}

enum state do_s3(void)
{
 printf("%s(#%d)\n", __FUNCTION__, __LINE__);
 return STATE_3;
}

enum state do_s4(void)
{
 printf("%s(#%d)\n", __FUNCTION__, __LINE__);
 return STATE_4;
}

enum state in_init(struct instance_data *data)
{
 printf("%s(#%d): do some init. E:%d\n", __FUNCTION__, __LINE__, data->evt);
 printf("change to S1\n");
 return STATE_1;
}
定義進入每一個狀態要執行的動作



int main( void ) {
 int ch;
 struct instance inst = {STATE_INITIAL, 0};
 while ( 1 ) {
  run_state(&inst);
  // do other program logic, run other state machines, etc
  printf("MENU: E1/E2/E3/E4\n");
  while(((ch = getc(stdin)) == '\n') || (ch <= '0') || (ch > '4'));
  inst.data.evt = ch - '0';
 }
}
main function模擬State Machine收到不同event(1~4)


以下是收到event 1, 2, 3, 4的執行結果





2017年7月8日 星期六

How to send a html email with the bash command "mail"/“sendmail”?


有時我們會需要透過Linux發送一些report mail,這時候我們就可以用mail這個指令
brook@vista:~/kernel$ ls | txt2html| mail --debug-level=7 -s 'show kernel floder' rene3210@gmail.com
mail: sendmail (/usr/sbin/sendmailn
mail: Getting auth info for UID 1003
mail: source=system, name=brook, passwd=x, uid=1003, gid=1000, gecos=,,,, dir=/home/brook, shell=/bin/bash, mailbox=/var/mail/brook, quota=0, change_uid=1
mail: Getting auth info for UID 1003
mail: source=system, name=brook, passwd=x, uid=1003, gid=1000, gecos=,,,, dir=/home/brook, shell=/bin/bash, mailbox=/var/mail/brook, quota=0, change_uid=1
mail: mu_mailer_send_message(): using From: brook@vista
mail: Sending headers...
mail: Sending body...
mail: /usr/sbin/sendmail exited with: 0
mail:

上面這個指令會送出raw data,mail看到的也是顯示一些HTML內容,如
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta name="generator" content="HTML::TextToHTML v2.51"/>
</head>
<body>
<p>AndroidKernel.mk<br/>
<strong>COPYING</strong><br/>
<strong>CREDITS</strong><br/>
Documentation<br/>
Kbuild<br/>
Kconfig<br/>
<strong>MAINTAINERS</strong><br/>
Makefile<br/>
<strong>README</strong><br/>
<strong>REPORTING-BUGS</strong><br/>
android<br/>
arch<br/>
block<br/>
crypto<br/>
drivers<br/>
firmware<br/>
fs<br/>
include<br/>
init<br/>
ipc<br/>
kernel<br/>
lib<br/>
linaro<br/>
mm<br/>
net<br/>
samples<br/>
scripts<br/>
security<br/>
sound<br/>
tools<br/>
usr<br/>
virt</p>

</body>
</html>

如果我們要支援"Multipurpose Internet Mail Extensions (MIME)"只要在subject後面接上"\nContent-Type: text/html"即可
brook@vista:~/kernel$ ls | txt2html| mail --debug-level=7 -s "$(echo -e "show kernel floder\nContent-Type: text/html")" rene3210@gmail.com

也可以用"sendmail"指令來傳送mail
(
echo "From: ${from}";
echo "To: ${to}";
echo "Subject: ${subject}";
echo "Content-Type: text/html";
echo "MIME-Version: 1.0";
echo "";
echo "${message}";
) | sendmail -t

(message=`ls| txt2html`
echo "From: rene3210@gmail.com;"
echo "To: rene3210@gmail.com,rene3210@gov.tw;"
echo "Subject: Quota"
echo "Content-Type: text/html;"
echo "MIME-Version: 1.0;"
echo "${message}";
echo -e"\n\n"
) |sendmail -t


參考資料: How to send a html email with the bash command “sendmail”?



2017年4月30日 星期日

pkg-config


簡介

現在的電腦系統使用許多library package供使用者使用,但是在不同的platform使用這些library package是一件很困難的事,pkg-config收集相關的資訊並且統一的API供開發人員使用。 pkg-config利用".pc"檔的格式,記錄了一些library相關的資訊,提供對應的information給開發人員使用,以ubuntu為例,這些檔案被放置在/usr/lib/x86_64-linux-gnu/pkgconfig、/usr/lib/i386-linux-gnu/pkgconfig與/usr/lib/pkgconfig等目錄,以下為directfb的.pc
brook@vista:~$ cat /usr/lib/x86_64-linux-gnu/pkgconfig/directfb.pc
prefix=/usr
exec_prefix=${prefix}
libdir=${prefix}/lib/x86_64-linux-gnu
includedir=${prefix}/include

Name: DirectFB
Description: Graphics and windowing library for the Linux frame buffer device
Version: 1.2.10
Requires: fusion direct
Libs: -L${libdir} -ldirectfb -lpthread
Libs.private: -L${libdir} -ldl
Cflags: -D_REENTRANT -I${prefix}/include/directfb
brook@vista:~$ pkg-config --list-all
file_name_of_library_or_package          Name_in_pc - Description_in_pc
...
direct                         Direct - DirectFB base development library
...

PC檔內容

.pc包含了事先定義好的variable(key=value)與description(Name: description),description有以下資訊
Name: library的name。
Description: library的簡述。
URL: library的相關URL。
Version: library的版號資訊。
Requires: library所需要的library,可能會包含所需的版號資訊(=, <, >, <= or >=)。
Requires.private: 與 Requires相似,用於static link。
Conflicts: library可能與某個library衝突的資訊,可能會包含衝突的版號資訊(=, <, >, <= or >=)。
Cflags: 使用該library所需的compiler flags。
Libs: 使用該library所需的link flags。
Libs.private: 與Libs相似,用於static link。

pkg-config操作

基本語法為pkg-config [input parameters] [LIBRARIES...]相關input參數可以參考man page
brook@vista:~$ pkg-config --modversion --print-errors directfb
1.2.10
brook@vista:~$ pkg-config --cflags --print-errors directfb
-D_REENTRANT -I/usr/include/directfb
brook@vista:~$ pkg-config --libs --print-errors directfb
-ldirectfb -lpthread -lfusion -ldirect -lpthread
brook@vista:~$ pkg-config --libs --static --print-errors directfb
-ldirectfb -lpthread -ldl -lfusion -ldirect -lpthread -ldl
brook@vista:~$ pkg-config --print-requires --print-errors directfb
fusion
direct
brook@vista:~$ pkg-config --print-requires --print-errors "directfb > 1.3"
Requested 'directfb > 1.3' but version of DirectFB is 1.2.10
brook@vista:~$ pkg-config --exists --print-errors directfb
brook@vista:~$ echo $?
0
brook@vista:~$ pkg-config --exists --print-errors directfbxx
Package directfbxx was not found in the pkg-config search path.
Perhaps you should add the directory containing `directfbxx.pc'
to the PKG_CONFIG_PATH environment variable
No package 'directfbxx' found
brook@vista:~$ echo $?
1

pkg-config實際應用

With GCC
brook@vista:~$ pkg-config --cflags --libs directfb
-D_REENTRANT -I/usr/include/directfb -ldirectfb -lpthread -lfusion -ldirect -lpthread
brook@vista:~$ gcc `pkg-config --cflags --libs directfb` -o myapp myapp.c

With autoconf and automake
configure.ac:
PKG_CHECK_MODULES([DIRECTFB], [directfb])

Makefile.am:
myapp_CFLAGS = $(DIRECTFB_CFLAGS)
myapp_LDADD = $(DIRECTFB_LIBS)

    參考資料:
  1. 簡介 pkg-config 的功能與用法, http://yczhuang.blogspot.tw/2007/04/pkg-config.html
  2. Guide to pkg-config, https://people.freedesktop.org/~dbn/pkg-config-guide.html#writing
  3. pkg-config 使用及建立方法, http://jyhshin.pixnet.net/blog/post/26588033-pkg-config-%E4%BD%BF%E7%94%A8%E5%8F%8A%E5%BB%BA%E7%AB%8B%E6%96%B9%E6%B3%95