結束上份工作後, 不想閒著, 也就開始找新"玩具",
做麵包好像滿有趣的, 又不用出門可以在家陪小朋友,
於是爬了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几度的高溫@@..
Friday, November 30, 2012
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
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
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介紹可參考:
為了能透過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. 客制開機畫面及背景圖
不過並不打算放上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
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
# 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
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
# 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
# ./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
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.
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.
* Threads
Android 提供以下的method, 可在其它的thread 下調用 UI thread.
Activity.runOnUiThread(Runnable)
View.post(Runnable) <-- used in example code.
View.postDelayed(Runnable, long)
View.post(Runnable) <-- used in example code.
View.postDelayed(Runnable, long)
或是使用Handler or AsyncTasks class 達到同樣的效果.
(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.
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:
Internally, AsyncTask uses fixed thread pool.
(See http://developer.android.com/reference/java/util/concurrent/ThreadPoolExecutor.html)
(See http://developer.android.com/reference/java/util/concurrent/ThreadPoolExecutor.html)
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;
}
}
}
Ref:
Subscribe to:
Posts (Atom)