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”?