Friday, November 30, 2012

About Bread!!

結束上份工作後, 不想閒著, 也就開始找新"玩具",
做麵包好像滿有趣的, 又不用出門可以在家陪小朋友,
於是爬了2~3天的文章,了解需要的東西,
Google什麼是yeast(Active dry, Instant dry, Fresh)?
什麼是麵粉(高筋, 中筋, 低筋, 法國粉)?
什麼是麵糰(擴展, 完成)?
什麼是揉麵?
天真的以為"吐司"很簡單,麵糰整好丟進烤模..done.
結果烤到第五條吐司, 才達成滿模的標準.

失敗品之一:


接著白吐司太無聊了, 所以做了其它嚐試,
全麥鮪魚麵包
高粉 270g
全麥粉 30g
Instant dry 3/4t
奶油 20g
塩 1/2t
糖 20g
水 185g

整形參考: 蒔蘿鮪魚麵包


海蒂的白麵包
配方跟做法參考 【肉桂打噴嚏】海蒂的白麵包


全麥豆漿枸杞葡萄乾
高粉 270g
全麥粉 30g
Instant dry 3/4t
奶油 20g
塩 1/2t
糖 20g
豆漿 185g
枸杞 + 葡萄乾 適量.


做了這些後, 深深感到...
萬能的雙手真的累人又吵, 尤其吐司要揉到完成階段.
再上鄰居來關切說: "你家是不是最近在釘東西?"...XD

於是開始Google解決辦法..
沒想到真的有人研發出No-Knead Bread...OMG

不過缺點是要"長時間發酵"..
後來又改善了長時間發酵的缺點:
Speedy No-Knead Bread
  
於是No-Knead Bread成了目前主要的做法
優點:
1. 免揉 == 不累沒噪音
2. 麵糰不加奶油 and 糖, 感覺較健康.
3. 我愛歐包的脆皮及咬勁
缺點:
麵糰水份高, 不易操作.

 使用陶鍋試了這個方法5次後, 覺得缺點還可以接受,
反正自己吃不用做美美的..XD
麵糰配方:
高粉 200g
Instant dry 1/8t
塩 1/4t
水 170~175g
 
今天特別做了一個大size的:
蜂蜜乾果全麥歐包, 乾果是葡萄乾+核桃
 
整形再發酵60分鐘就入烤箱了,
烤箱中的大陶鍋, 上色時表皮的乾果烤焦了..
 
出爐几分鐘後還量了一下,
沒想到裡面還有90几度的高溫@@..

Wednesday, September 12, 2012

How to split boot.img and get kernel config.

boot_cm9.img  file from mk802_legacy-compatibility_v1.zip
Device: Rikomagic MK802
Script files : Split_bootimg.pl , extract-ikconfig ( in {kernel_source}/script )

1. split boot.img
$ mkdir split_boot
$ cd split_boot
Copy boot_cm9.img, Split_bootimg.pl, extract-ikconfig into 'split_boot'
$ ./split_bootimg.pl boot_cm9.img
Page size: 2048 (0x00000800)
Kernel size: 8094708 (0x007b83f4)
Ramdisk size: 178940 (0x0002bafc)
Second size: 0 (0x00000000)
Board name:
Command line: console=ttyS0,115200 rw init=/init loglevel=8
Writing boot_cm9.img-kernel ... complete.
Writing boot_cm9.img-ramdisk.gz ... complete.

Get kernel image (boot_cm9.img-kernel) and ramdisk (boot_cm9.img-ramdisk.gz)

2. extract kernel config
$ dd if=boot_cm9.img-kernel of=dd_uImage bs=1024 skip=1
7903+1 records in
7903+1 records out
8093684 bytes (8.1 MB) copied, 0.0178518 s, 453 MB/s
$./extract-ikconfig dd_uImage > kernel_config


3. extract ramdisk
$ mkdir ramdisk
$ cd ramdisk
$ gzip -dc ../boot_cm9.img-ramdisk.gz | cpio -i
6677 blocks
$ tree .
.
├── data
├── default.prop
├── dev
├── init
├── init.goldfish.rc
├── initlogo.rle
├── init.rc
├── init.sun4i.rc
├── init.sun4i.usb.rc
├── proc
├── sbin
│   ├── adbd
│   └── ueventd -> ../init
├── sys
├── system
├── ueventd.goldfish.rc
├── ueventd.rc
└── ueventd.sun4i.rc


Ref : HOWTO: Unpack, Edit, and Re-Pack Boot Images

Tuesday, August 21, 2012

How to extract kernel config from uImage

How to extract kernel config from uImage
1. get extract-ikconfig in kernel-source/scripts/
$mkdir extreact-uImage
$cd extreact-uImage
$cp {kernel-source}/scripts/extract-ikconfig .

2. dump uImage skip 1024 bytes
$cp {uImage/what/you/want} uImage
$dd if=uImage of=dd_uImage bs=1024 skip=1
$./extract-ikconfig dd_uImage > config

Sunday, July 29, 2012

XBMC for Android on MK802

XBMC announce XBMC for Android.
不過並不打算放上Google Play, 需要自行compile及打包, 方法可參考:
Build XBMC for Android on lubuntu 12.04

在此記錄一下目前在MK802跑起來的情況.
MK802介紹可參考:

Android 4.0 mini PC 最小的主機MK802

CPU : Allwinner A10 - ARM Cortex A8 SoC

GPU : ARM Mali 400
RAM : 1GB
以公定價$79USD及讓人跌破眼鏡的入手價, 拿來玩真是夠本了.
這次是要用Android 手機來控制 XBMC, 因為MK802沒有IR只能用滑鼠操作上有些不便.
Google Play上有Official XBMC Remote可直接下載來用.
中文設定: 切換到Appearance -> Setting -> International -> Language
為了能透過HTTP連到MK802的XBMC, 需要將"網站伺服"的功能打開, 設定port number
接著查看IP, 設定手機上的XBMC Remote如下:
連線成功就會出現控制選項
用手機上"Remote Control" Navigation, 測試播放USB裡的影片,
影片開播後選手機上的"Now Playing", 可以做seek, FF/FB功能,
音量控制是使用手機上的音量鍵.(當初還因為無法控制音量煩腦, 沒想到直接用就可以...冏)
播放online radio, 用的是SKY.FM, 可以到"附加元件"中下載安裝.
音樂Full screen播放, 可以看到背景的GL動畫還可以跑到31fps, 似乎還OK.
天氣+音樂播放, 後面的GL動畫還是正常顯示, 並不是靜態的.

後記:
1. 透過附加元件下載安裝的YouTube及Time.com無法正常播放video.
2. 很吃記憶體大約要吃掉80MB.
3. 研究XBMC在Android 如何implement, 應該是很有趣的.必竟XBMC是用自己的GUI系統, 還要克服Bionic libc在dlopen的不足之處. 


Update:
XBMC APK 下載
APK修改的部份:
1. 修正中文無法顯示問題.
2. 客制開機畫面及背景圖

Saturday, July 28, 2012

Build XBMC for Android on lubuntu 12.04


1. install required packages
# sudo apt-get install build-essential default-jdk git curl autoconf \
   unzip zip zlib1g-dev gawk gperf

2. Getting the Android SDK and NDK
crystax-5 NDK with enabled support of C++ exceptions, RTTI and Standard C++ Library 

3.Installing Android SDK packages
<android-sdk> : $HOME/XBMC_Project/android-sdk-linux
# cd <android-sdk>/tools
# ./android update sdk -u -t platform,platform-tool

4.Setup the Android toolchain
<android-ndk> :  $HOME/XBMC_Project/android-ndk-r8b
<android-toolchain> :  $HOME/XBMC_Project/android_toolchain/android-9
# cd <android-ndk>
# ls platforms
# cd build/tools
# ./make-standalone-toolchain.sh --ndk-dir=../../ \
  --install-dir=<android-toolchain>/android-9 --platform=android-9

5. Create a (new) debug key to sign debug APKs
All packages must be signed. The following command will generate a
self-signed debug key. If the result is a cryptic error, it
probably just means a debug key already existed, no cause for alarm.

# keytool -genkey -keystore ~/.android/debug.keystore -v -alias \
  androiddebugkey -dname "CN=Android Debug,O=Android,C=US" -keypass \
  android -storepass android -keyalg RSA -keysize 2048 -validity 10000

6. Getting the source code
# cd $HOME/XBMC_Project
# git clone git://github.com/xbmc/android.git xbmc-android-git
# cd xbmc-android-git
# git submodule update --init addons/skin.touched

7.Building dependencies
# cd $HOME/XBMC_Project/xbmc-android-git/tools/android/depends
# ./bootstrap
# ./configure --help
#export XBMC_ANDROID_NDK=~/XBMC_Project/android-ndk-r7-crystax-5.beta2
#export XBMC_ANDROID_SDK=~/XBMC_Project/android-sdk-linux
#export XBMC_ANDROID_TARBALLS=~/XBMC_Project/xbmc-tarballs
#./configure --with-toolchain=~/XBMC_Project/android-toolchain/android-9
checking for g++... g++
checking whether the C++ compiler works... yes
checking for C++ compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C++ compiler... yes
checking whether g++ accepts -g... yes
checking for gcc... gcc
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking for main in -lz... yes
checking for unzip... yes
checking for zip... yes
checking for curl... /usr/bin/curl
checking for tar... /bin/tar
checking for -gcc... no
configure: WARNING: host was not specified. guessing.
checking for gcc... /home/oopsmonk/XBMC_Project/android-toolchain/android-9/arm-linux-androideabi/bin/gcc
        toolchain:       /home/oopsmonk/XBMC_Project/android-toolchain/android-9
        cpu:             armeabi-v7a
        host:            arm-linux-androideabi
        sdk-platform:    android-10
configure: creating ./config.status
config.status: creating Makefile
config.status: creating Makefile.include
#make -j4
make[1]: Leaving directory `/home/oopsmonk/XBMC_Project/xbmc-android-git/tools/android/depends/libssh'
Dependencies built successfully.

8.Building XBMC
#cd ~/XBMC_Project/xbmc-android-git/tools/android/depends/xbmc
#make -j4
APK location : ~/XBMC_Project/xbmc-android-git/xbmcapp-armeabi-v7a-debug.apk
Enjoy it !!

Ref: 

Thursday, June 14, 2012

[Note]Android Threads, Handlers and AsyncTask


先看過Processes and Threads會有比較清楚的概念
當Adnroid Application 啟動後, 系統會建一個主要的thread 稱 "main thread" or "UI thread", 所有的components 皆跑在這個UI thread, system calls 也是透過UI thread dispatched給各個component, ex: onKeyDown, touch event.
UI thread 如因大量運算或等待而blocked, 預設超過5秒ANR(Application Not Responding)就會發生.
且Android UI components 並非thread-safe, 使用上要特別小心.
所以:
1. long time computation使用另外的thread, 不要寫在 UI Thread.
2. 不要在UI thread 之外使用UI component method.
透過Thread, Handler and AsyncTask perform asynchronous processing, 避免UI thread block.

Android 提供以下的method, 可在其它的thread 下調用 UI thread.
Activity.runOnUiThread(Runnable)
View.post(Runnable) <-- used in example code.
View.postDelayed(Runnable, long)
或是使用Handler or AsyncTasks class 達到同樣的效果.

* Handler
有2個主要用途:
(1) message scheduling,  post action at specific point.
(2) 將其它thread發出來的action 放入message queue中, 避免race condition.
 
處理message 需要override handleMessage(), 透過sendMessage() or sendEmptyMessage() method.
執行Runnanble則是使用post() method.
一個Activity 只需有一個Handler instance.

* AsyncTask
使用AsyncTask必需繼承它, 且override doInBackground() method.

4 steps:
呼叫execute() 開始執行, 之後onPerExecute()接著自動被呼叫, 通常用來 initial status of task.
接著doInBackground() 被調用, 一般為long time computation時使用.
call publishProgress()後會調用onProgressUpdate(), onProgressUpdate()調用於UI thread, 一般用來update progress bar, UI animate.
publishProgress() trigger時間點是無法預期的.
doInBackground() 結束後會trigger onPostExecute()調用於UI thread, 用來返回結果.
 
* Thread, Handler 在Avtivity 結束後 thread就結束, 但AsyncTack則否.
Ans: 
So, even if AsyncTask finished, thread does not die. But thread in thread pool can be killed.
 
Examples
Layout XML file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/run" />

    <ProgressBar
        android:id="@+id/progressBar1"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="60dp" />

</LinearLayout>
 
Thread example code:
package com.samchen.samdemos.threads;

import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;

public class DemoThreads extends Activity {
    final boolean isThread = true;
    final String TAG = "DemoThreads";
    private ProgressBar mProgress;
    private int mProgressStatus = 0;
    boolean isRunning = false;
   
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.demothreads);

        Button btnRun = (Button) findViewById(R.id.button1);
        mProgress = (ProgressBar) findViewById(R.id.progressBar1);

        btnRun.setOnClickListener(new Button.OnClickListener() {

            @Override
            public void onClick(View arg0) {
                if(isRunning){
                    Log.d(TAG,"thread is runing");
                    Toast.makeText(getApplicationContext(),
                            getString(R.string.running),
                            Toast.LENGTH_SHORT).show();
                    return;
                }else
                    isRunning = true;
               
                if (isThread) {
                    // thread example
                    new Thread(new Runnable() {
                        public void run() {
                            while (mProgressStatus < 100) {
                                // update the bar status
                                mProgress.post(new Runnable() {
                                    public void run() {
                                        mProgress.setProgress(mProgressStatus);
                                        Log.d(TAG, "update mProgressStatus : "
                                                + mProgressStatus);
                                    }
                                });

                                // do something long
                                SystemClock.sleep(500);
                                mProgressStatus++;
                            }
                        }

                    }).start();

                } else {
                    // non-thread example
                    while (mProgressStatus < 100) {
                        // update the bar status
                        mProgress.post(new Runnable() {
                            public void run() {
                                mProgress.setProgress(mProgressStatus);
                            }
                        });

                        // do something long
                        //SystemClock.sleep(500);
                        //if use SystemClock.sleep, system will be crash.
                        try{
                            Thread.sleep(500);
                        }catch (InterruptedException e){
                            Log.d(TAG,"InterruptedException!!!!!!!");
                            e.printStackTrace();
                        }
                        mProgressStatus++;
                       
                    }
                }

            }

        });
    }

}

Handler example:
package com.samchen.samdemos.threads;

import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;

public class DemoHandler extends Activity {

    final String TAG = "DemoHandler";
    private ProgressBar mProgress;
    private int mProgressStatus = 0;
    private Handler mHandler;
    boolean isRunning = false;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.demothreads);

        Button btnRun = (Button) findViewById(R.id.button1);
        mProgress = (ProgressBar) findViewById(R.id.progressBar1);
        mHandler = new Handler();

        btnRun.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                if (!isRunning) {
                    startProgress(mProgress);
                    isRunning = true;
                } else{
                    Log.d(TAG, "thread is runing");
                    Toast.makeText(getApplicationContext(),
                            getString(R.string.running),
                            Toast.LENGTH_SHORT).show();
                }
            }
        });

    }

    public void startProgress(View view) {
        // Do something long
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                for (mProgressStatus = 0; mProgressStatus <= 100; mProgressStatus++) {
                    //final int value = i;
                    SystemClock.sleep(500);
                   
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            Log.d(TAG, "update mProgressStatus : "
                                    + mProgressStatus);
                            mProgress.setProgress(mProgressStatus);
                        }
                    });
                }
            }
        };
        new Thread(runnable).start();
    }
}

AsyncTask example:
package com.samchen.samdemos.threads;

import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;

public class DemoAsyncTask extends Activity {

    final String TAG = "DemoAsyncTask";
    private ProgressBar mProgress;
    private int mProgressStatus = 0;
    boolean isRunning = false;
    private updateTask mTask;

    /** Called when the activity is first created. */

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.demothreads);

        mProgress = (ProgressBar) findViewById(R.id.progressBar1);

        Button btnRun = (Button) findViewById(R.id.button1);
        btnRun.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                if (!isRunning) {
                    mTask = new updateTask();
                    mTask.execute();
                    isRunning = true;
                } else {
                    Log.d(TAG, "thread is runing");
                    Toast.makeText(getApplicationContext(),
                            getString(R.string.running), Toast.LENGTH_SHORT)
                            .show();
                }
            }
        });

    }

    private class updateTask extends AsyncTask<Void, Integer, Void> {

        protected void onPostExecute(Void result) {
           
        }

        protected void onProgressUpdate(Integer... value) {
            Log.d(TAG, "onProgressUpdate : " + value);
            mProgress.setProgress(value[0]);
        }

        protected void onPreExecute() {
            // TODO Auto-generated method stub
            mProgressStatus = 0;
        }

        protected Void doInBackground(Void... params) {
            // TODO Auto-generated method stub

            while (mProgressStatus < 100) {
                Log.d(TAG, "doInBackground mProgressStatus : "
                        + mProgressStatus);
                // do something long
                publishProgress(mProgressStatus);
                SystemClock.sleep(500);
                mProgressStatus++;
            }
            return null;
        }
    }

}