2019年6月30日 星期日

Onyx Boox Note Lite 沒有回應

2 月中購買到現在,一直都用得好好的,昨天睡覺前還在看《七個會議》,今天早上起來,螢幕總是呈現休眠畫面,不論怎麼按下電源鍵都沒有回應,打開電腦接上 USB 線也無法順利抓到裝置,故想使用 ADB Tool 來 debug 也無法成行,看來只能送修了。

有點後悔購買大陸品牌了,就為了貪圖 Android 開放式系統的自由,卻換來不到半年的使用!更何況我個人擁有 4 台電子書閱讀器,最常用的也是 Kindle Paperwhite 3,實在輪不到 Note Lite 出毛病,開始擔心我的另一台 Nova Pro 了。

《七個會議》正看到精采處,真的是無語問蒼天。

2019/07/01 更新
這個人的問題跟我很像,但是並沒有後續結果。只好先聽賣家的建議,充電 2 個小時以上看看,目前只知道快沒電時自動關機螢幕會是關機畫面而不是休眠待機畫面,而我的畫面是休眠畫面,星期六下午才充飽電,晚上到睡覺前應該看不到 2 個小時的書。

http://bbs.onyx-international.com/t/unable-to-charge/623/5


2019/07/02 更新
剛又看到另外一個例子,但他比較幸運,應該是不知道為什麼電被耗完了自動關機,理論上只要把電流充進去就可以恢復正常,可惜本人英文不好,沒辦法回答他。

https://www.mobileread.com/forums/showthread.php?t=321155


2019/08/02 更新
又在 2018/06 看到一個例子,這個比例好像有點高?

2019年6月28日 星期五

魔術數字 0xED3A65B4CB4B34E9

Hamming (72,64) 演算法中,目前知道 extra parity 8 有 2 種算法:
1. XORing all data bits.
2. step1 plus XORing parity 1 ~ parity 7.

我之前用的都是 1 的作法,知道 2 的作法後,終於解答了 0xED3A65B4CB4B34E9 這個魔術數字的算法,Rust 的 sample code 如下:

fn main() {
    let p1: u64 = 0xDAB5556A_AAAAAAD5;
    let p2: u64 = 0xB66CCCD9_999999B3;
    let p3: u64 = 0x71E3C3C7_8787878F;
    let p4: u64 = 0x0FE03FC0_7F807F80;
    let p5: u64 = 0x001FFFC0_007FFF80;
    let p6: u64 = 0x0000003F_FFFFFF80;
    let p7: u64 = 0x00000000_0000007F;
    let p8: u64 = 0xFFFFFFFF_FFFFFFFF;

    let another_p8 = p1 ^ p2 ^ p3 ^ p4 ^ p5 ^ p6 ^ p7 ^ p8;

    println!("0x{:X}", another_p8);
}


2019年6月26日 星期三

讀墨購書金額破萬紀念日

到昨天為止,在讀墨購書金額正式累計破萬,我想這個數字應該會持續增加吧!

一直到 2018 下半年,我才知道有讀墨和樂天可以購買繁體中文書,以前我都只在 Amazon 購買英文技術書並在 Kindle Paperwhite 3上看書。

不得不說有了這些網站後,看電子書真的是更方便了,漸漸的我也比較少看英文的技術書了。

有在看書的人就知道,看書最大的敵人就是時間不夠用,每天下班後看書的時間實在有限,更別提還要撥出時間與家人相處。

讀墨也是讓我開始學習 Chrome Extension 的原因,之前想學一直抽不出空來,為了方便取得購買的書籍清單,也讓我多學會了一樣技能,雖然對工作沒什麼多大幫助就是了。

讀萬卷書,行萬里路,我想能限制我們人類的,大概也只剩時間了吧。

Rust 探索之旅 - 撞牆期開始

到目前為止,我最喜歡 Rust 的一個地方是它可以使用 "_" 來分隔數字,可以當千分位號使用,也可以分隔 16 進位數字,後者應該是我們程式設計師最常使用的。

最近在整理上禮拜看的一個演算法,其中有一些魔術數字,由於位數太多,實在很容易在 porting code 時出錯,剛好我已經完成 C 語言的版本,故想使用目前為止會的 Rust 來實作看看,殊不知開始進入了瘋狂 google 的地獄輪迴。

細節就不多說了,總之就是花了一個早上,才寫出這個 100 行的程式,開始有點懷念 Go 了,雖然我也很久沒寫了,距離上一次使用 Go 寫測試程式也有一年多了吧?

2019/06/27 更新
使用 rustfmt 重新排版 code。

重點提示
01. 函數只能有一個回傳值,參數要寫型別。
02. Data Type 真的有一種型別叫 "usize"。
03. 型別不符時,可以使用 "as" 轉型。
04. "print!" 不會換行,故可能會存在 Buffer 無法印出,使用 flush 清空 Buffer。

use std::io;
use std::io::Write;
use std::u64;

const BIT_TABLE: [u8; 16] = [0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4];

fn get_parity_bit(data: u64) -> u8 {
    let mut odd_bit_count: u8 = 0;
    let mut step: u8 = 0;

    let mut n: u64 = data;
    let mut index: u64;

    for _i in 0..16 {
        n = n >> step;

        index = n & 0x00000000_0000000F;
        odd_bit_count += BIT_TABLE[index as usize];

        step = 4;
    }

    if odd_bit_count % 2 == 0 {
        return 0;
    }

    return 1;
}

fn get_parity(data: u64) -> u8 {
    let p1 = get_parity_bit(data & 0xDAB5556A_AAAAAAD5);
    let p2 = get_parity_bit(data & 0xB66CCCD9_999999B3);
    let p3 = get_parity_bit(data & 0x71E3C3C7_8787878F);
    let p4 = get_parity_bit(data & 0x0FE03FC0_7F807F80);
    let p5 = get_parity_bit(data & 0x001FFFC0_007FFF80);
    let p6 = get_parity_bit(data & 0x0000003F_FFFFFF80);
    let p7 = get_parity_bit(data & 0x00000000_0000007F);
    let p8 = get_parity_bit(data & 0xFFFFFFFF_FFFFFFFF);

    println!("p1 = {}", p1);
    println!("p2 = {}", p2);
    println!("p3 = {}", p3);
    println!("p4 = {}", p4);
    println!("p5 = {}", p5);
    println!("p6 = {}", p6);
    println!("p7 = {}", p7);
    println!("p8 = {}", p8);

    // The MSB is p8
    let parity_bit = p8 << 7 | p7 << 6 | p6 << 5 | p5 << 4 | p4 << 3 | p3 << 2 | p2 << 1 | p1;

    return parity_bit;
}

fn main() {
    let mut num: String;

    let mut data: u64;
    let mut p: u8;

    loop {
        print!("Please input hex integer(8 byte - 8F7F6F5F4F3F2F1F): ");
        io::stdout().flush().expect("Can't flush buffer");

        num = String::new();
        io::stdin()
            .read_line(&mut num)
            .expect("Failed to read line");

        num = num.trim().to_string();

        if num == "q" {
            println!("Bye Bye");
            break;
        }

        if num.len() != 16 {
            println!("Please input hex integer with 16 {} {}", num.len(), num);
            continue;
        }

        println!("");

        data = u64::from_str_radix(&num, 16).expect("Failed to convert to integer");
        p = get_parity(data);

        println!("--------------------------------------");
        println!("data   = 0x{:016X}", data);
        println!("parity = 0x{:02X}", p);
        println!("-------------------------------------- \n");
    }
}

2019年6月21日 星期五

專業人士

小飛俠 ─ Koby Bryant 曾經講過一句話:「你見過凌晨四點的洛杉磯嗎?」,其實,年紀大了,我也常常見到凌晨四點的 Taiwan 街頭XD

今天,又是個睡不著早起的日子,起來看了一下昨天搞不懂的演算法,還不到七點就出門坐公車,反正時間也還很早,往前走一站去享受公車起站有位子坐的悠閒。

七點的咖啡廳果然沒有什麼人?點了一杯奶茶,聽著輕音樂,安靜的看著《软技能:代码之外的生存指南》,感覺生產力都增加了不只一個檔次。

身為一個專業人士,隨身攜帶電子書閱讀器也是很合理的,想看什麼書就看什麼書,畢竟裡面也裝了不少御三家的書籍。

我果然還是最喜歡 Kindle Paperwhite 3,有了它之後,頭腦變得更聰明,考試也都考一百分。

知識無價

最近幫忙看個東西,雖然我不是 owner,但既然看了,還是想把它弄懂,可惜本人英文不太好,看了好多網站還是似懂非懂,後來剛好在 Google Play 圖書看到紙本書的試閱章節,順利的解決了我心中的疑惑!

有常買 Amazon.com 技術書籍的人就知道,有些書的英文看起來就是特別舒服,這本書就是其中之一。

雖然這本書我後來先找到謎版!但在發現能夠購買 PDF 的網站後,不囉嗦的立馬下訂了,能夠把知識寫得淺顯意懂,不支持它真的是太說不過去了。

更何況這本書只要 US$67.79,我覺得真的是太便宜了。目前這本書價錢暫時超越 C11 規格書,成為我最貴的電子書排行榜第一名。

2019年6月20日 星期四

Connect to China by PureVPN

為了永遠解決 Amazon.cn 買了幾本書﹝據上上次客服說法是 20 本﹞,就要拜託客服人員解鎖的問題。研究了幾家付費 VPN,目前在網站伺服器列表中還有 China 選項的似乎只剩下 PureVPN,故花了 US$10.95 買了一個月的帳號來測試,據實測的結果,可以順利的連到上海伺服器,在 "What Is My IP?" 上看到的位置也是顯示上海無誤,也可以成功的在 Amazon.cn 上購買書籍﹝還未到達鎖定狀態,故可能不準﹞。

不過,據網路上的說法,雖然標榜 no log or no records,但還是會在 Server 上留下隱私資料,故要使用的人請自己決定。

順帶一提,Chrome Extension 沒有 China 選項可以選,故我測試是使用 Windows 軟體,作業系統為 Windows 7。


2019/10/14 更新

PureVPN 預設會自動續約,印象中當初申請似乎沒有選項可以調整,故只是想試用的話,記得要取消,否則會被一直自動扣款。

取消方式只能用線上 chat,只要告知客服想要 stop 帳戶即可。

2019年6月19日 星期三

Rust 探索之旅 - 變數宣告

Rust 是靜態型別的程式語言,理論上我們在宣告變數時,需要寫出型別。

不過,compiler 會跟據後面的值來自動推導型別,故我們可以省略型別宣告。將型別放在變數名稱後面,是幫助 compiler 更容易的去 parsing 原始檔。

let num = 32;
let num: u8 = 32;

另外,我們會用一種 shadow 的技巧,來避免使用太多變數名稱。注意,第 1 個 money 和第 2 個 money 是不同的變數,第 1 個 money 會被第 2 個 money 屏蔽。這裡我們不能在第 1 個 money 使用 "mut" 關鍵字而不使用 "let" 在第 2 個 money 變數上,否則會導致型別不同,不能改值。

數字可以參考千分位符號的概念,加上 '_' 字元好方便閱讀。此外,如果是沒使用到的變數,可以在變數名稱前加上 "_",以避免 compiler warning。

let money = "100000";  // from some function
let money =  100_000;
let _x = 1;

2019年6月18日 星期二

VIM 取代 ^M

每次要用到時都要再 google 一下,乾脆記在 Blog 好了。

步驟如下
1. vim 檔案
2. :%s/^M//g

:  表示要進入命令列模式。
%   表示全域。
^M  表示要取代 \r,需用 Ctrl + V + enter 按出。
//  表示用空的東西取代 ^M。
g   表示整行全部。

亞馬遜繁體中文書後續觀察指標

到今天 2019/06/18 為止已經過了 3 個星期,繁體中文書的增加速度不如預期,很多主打的書早就在 Readmoo 或是 Kobo 購買過了。

我覺得 3 個月是 1 個很重要的觀察指標,如果 3 個月後,繁體中文的書量還是跟現在差不多,那我覺得也不用抱太大的期望了!

最糟狀況就是購買 Android 電子書閱讀器,然後跟 Amazon 繁體中文書說 bye bye 吧。

雖然我早就有 2 台文石機器,但還是衷心的希望能在 Kindle 閱讀器上看繁體中文書。

2019年6月17日 星期一

Rust 探索之旅 - Cargo

Cargo 除了是編譯工具,也是 Rust 的套件管理工具。

在 Rust 語言裡,我們會稱呼模組為 crate,如果需要什麼模組,我們可以來 https://crates.io/ 找尋是否有現成的可以用。

之前文章中提到,我們可以用 cargo 來初始專案,專案資料夾內會有一個 Cargo.toml 的設定檔,其中 [dependencies] 區塊就是用來宣告我們使用到的其他模組。

我們只要簡單的加入模組名稱及版本號,執行 cargo build 時,便會去下載模組。
[dependencies]
rand = "0.3.14"
另外,第一次執行  cargo build 時,會產生一個 Cargo.lock 檔案,裡面會記錄相關模組的版本,這個機制可以確保別人在編譯專案時,會跟開發者當初使用的一致。

2019年6月16日 星期日

Onyx Boox 閱讀器叫出內建設置

文石系統由於有自己的 Launcher ,其 App 清單中並無設置,故無法叫出內建的設置頁面。

網路上說可以透過 adb 解決,我雖然沒用過,但原理應該是透過 adb 來啟動設置 App。

我覺得對一般使用者來說,應該有更簡單的方式,那就是安裝任一 Launcher App,比如說 Nova Launcher,便可以在它的 App 清單中找到設置 App,如果沒有想取代原本 Launcher,記得詢問時選僅此一次即可。

2019年6月13日 星期四

UEFI Application - Get Boot Variables

在搞懂了相關結構後,剩下的就是 coding 了,在 UDK Base 翻找後,便寫出了下面的程式,可以讀取所有的 Boot Variables,Just for fun。


#include <stdio.h>
#include <Library/UefiLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/PrintLib.h>
#include <Library/BaseLib.h>
#include <Library/DevicePathLib.h>

// The caller is responsible for freeing this buffer with FreePool().
VOID* mGetVariable(CHAR16 *name, EFI_GUID *guid, UINTN *size)
{
    EFI_STATUS  status;
    UINTN       realSize;
    VOID        *value;

    // Try to get the variable size.
    value = NULL;
    realSize = 0;
    status = gRT->GetVariable(name, guid, NULL, &realSize, value);
    if (status != EFI_BUFFER_TOO_SMALL) {
        return NULL;
    }

    // Allocate buffer to get the variable.
    value = AllocatePool(realSize);
    if (value == NULL) {
        return NULL;
    }

    // Get the variable data.
    status = gRT->GetVariable(name, guid, NULL, &realSize, value);
    if (EFI_ERROR(status)) {
        FreePool(value);
        return NULL;
    }

    *size = realSize;
    return value;
}

int main(void)
{
    VOID *value;
    UINTN size;

    UINTN varCount;
    UINTN i;

    UINT16 bootString[10];
    UINT16 *desc;

    UINT16 filePathLen;
    EFI_DEVICE_PATH_PROTOCOL *protocol;

    char *ptr;

    value = mGetVariable(L"BootOrder", &gEfiGlobalVariableGuid, &size);
    if (value == NULL) {
        printf("Can't get BootOrder Variable \n");
        return -1;
    }

    FreePool(value);

    varCount = size / 2;
    for (i = 0; i < varCount; i++) {
        UnicodeSPrint(bootString, sizeof(bootString), L"Boot%04x", i);

        value = mGetVariable(bootString, &gEfiGlobalVariableGuid, &size);
        if (value == NULL) {
            printf("Can't get Boot%04X Variable \n", i);
            return -1;
        }

        ptr = (char*)value;

        desc = (UINT16*)(ptr + 6);
        Print(L"Boot%04X : %s \n", i, desc);

        filePathLen = *((UINT16*)(ptr + 4));
        protocol = (EFI_DEVICE_PATH_PROTOCOL*)(ptr + 6 + 2*(StrLen(desc)+1));

        Print(L"FilePath Length %02X \n", filePathLen);
        Print(L"FilePath.Type %02X \n", protocol->Type);
        Print(L"FilePath.SubType %02X \n", protocol->SubType);
        Print(L"%s \n", ConvertDevicePathToText(protocol, TRUE, TRUE));
        Print(L"\n");

        FreePool(value);
    }

    return 0;
}

Boot0000 : USB: ADATA USB Flash Drive 
FilePath Length 27 
FilePath.Type 05 
FilePath.SubType 01 
BBS(HD,USB: ADATA USB Flash Drive) 

Boot0001 : UEFI USB: ADATA USB Flash Drive 
FilePath Length 1C 
FilePath.Type 02 
FilePath.SubType 01 
PciRoot(0x0)/Pci(0x10,0x7)/USB(0x3,0x0) 

Boot0002 : Internal EDK Shell 
FilePath Length 2C 
FilePath.Type 04 
FilePath.SubType 07 
Fv(92E111AA-5F63-49D5-96C7-947422BDD1AA)/FvFile(C57AD6B7-0515-40A8-9D21-551652854E37) 

電子書閱讀器手感

我開始相信重量真的不是絕對了!

一直都覺得 Note Lite 拿起來比 Nova Pro 舒服,但其實還多了 85 克,大概等於一個瑜伽磚的感覺,我想也許是因為 Note Lite 較薄的關係或是 Nova Pro 重量分佈的問題,總之,開始有點想把 Nova Pro 賣掉了!

也不是說 Nova Pro 不好,但凡事在使用比較後就會見真章,坦白說,當初拿到 Nova Pro 驚為天人的感覺已經所剩無幾!也許,對我來說,Nova Pro 只剩攜帶方便這個優點,畢竟我並沒有把御三家的書全部轉進 Kindle Paperwhite 3。

看著自己的暗黑心法原始碼,只能感嘆為什麼 Kindle 不支援 EPUB 格式就好,這樣我就少掉每次轉檔時還要花時間 debug kindlegen 所吐出來的錯誤訊息了。

2019年6月12日 星期三

Rust 探索之旅 - Can't work on Windows 7

執行 cargo -V or rustc -V 時,程式就沒反應,不論是用工作管理員或是 taskkill 指令都無法停止相關程式,目前只知網路上的看法是跟防毒軟體有關。

遇到這種問題時,連關機都無法正常,只能強制斷電,已經斷電了 3 次。

我個人認為是跟 wrapper 的檔案有關﹝user/.cargo/bin﹞,而不是真實的執行檔有問題﹝user/.rustup/toolchains/stable-x86_64-pc-windows-msvc/bin﹞,也許可以把真實的執行檔加入到 PATH,而不要使用 wrapper 的位置?

https://github.com/rust-lang/rustup.rs/issues/1075
https://github.com/rust-lang/cargo/issues/3673

2019/06/18 更新
砍掉 "user/.cargo" 裡的 cargo.exe and rustc.exe,直接使用 "user/.rustup" 的執行檔就正常了,記得把這個路徑加入到 PATH

Rust 探索之旅 - Hello World

早上坐公車時無聊,看了一下 Rust 教學文件,開始我的 Rust 探索之旅。

Rust 和 C 一樣,都是編譯型語言,透過編譯會得到一個單一執行檔,可以方便的發佈給其他人。不像 script language,對方要執行時,需要有相關的安裝環境﹝理論上的,因為有些語言有第三方工具可以 build executable binary ﹞。

Rust 目前已知特點
01. cargo new "helloworld",可以自動建立一個 "helloworld" 的專案,"helloworld" 資料夾裡面會有 git 結構、Cargo.toml 的專案描述檔以及一個建立好的 "src\main.rs" 程式碼檔案,副檔名 "rs" 表示這是一個 Rust 的原始碼檔案。
02. 同 Go 一樣,cargo run 可以直接執行,cargo build 則是編譯 binary。
03. Rust 使用 let 宣告變數,變數預設是 immutable,加上 mut﹝mutable﹞表示變數可以被改值。
04. Rust 使用 use 宣告來存取內建函數。
05. "println!" 是一個 macro 而不是函數。
06. StringUTF-8 的編碼。
07. & 表示傳進函數的是一個參考﹝reference﹞,也可以加上 mut 關鍵字。
08. 在 println 中,"{}" 表示一個佔位符,有幾個後面就要有幾個對應的變數。
09. read_line包含換行字元,因為我們是 String,可以用 num.trim( ) 來去除。
10. Rust 變數命名慣例是小寫駝峰式,例如:s_len。


use std::io;

fn main() {
    println!("Guess the number");
    println!("Please input your guess");

    let mut num = String::new();

    io::stdin().read_line(&mut num)
        .expect("Failed to read line");

    println!("Your guess: {}", num);

    let s_len = num.len();
    let bytes = num.into_bytes();
    println!("lenth = {}, bytes = {:?}", s_len, bytes);
}

C:\helloworld>cargo run
Guess the number
Please input your guess:
123
Your guess: 123

lenth = 5, bytes = [49, 50, 51, 13, 10]

C:\helloworld>

2019年6月11日 星期二

目前為止買過最貴的書 - ISO/IEC 9899:2011

人生到目前為止,買過最貴的書,就是 C11 規格書(約台幣 NT 1,884)。

沒辦法,最新標準 C18 要瑞士法郎 198﹝約台幣 NT 6,256﹞,實在是太貴買不下去。只好退而求其次,買前一個標準 C11,不管怎樣,也比我當初學的 C89 還要新。

2019年6月10日 星期一

UEFI Application - 找出 UEFI 相關函數實作

寫 UEFI Application 時,如果是跟 UEFI 有關的東西,常常需要去 UDKBase 裡翻找,我一般都是使用 "FileSeek v3.3" 這個工具,可以幫助我很快的找到關鍵字。可惜的是,即使發現在某支 .c 檔,如果想要在該檔案中查找相關函數,我目前用的 UltraEdit 並沒有辦法在函式清單中列出來所有函數,這個是跟 UEFI 慣用的函式實作寫法有關,目前至少發現有 2 種寫法,故我後來都是使用 grep 來找出函式名稱。

 Rgex 下法
1. "^\w+\s*\("

兩者的差別在函數名稱後面到左括弧間有無空格,之後如果有新發現再來補充。

2019年6月6日 星期四

UEFI - flexible array member

為了研究 Boot Variable,在 header file 看到一個很特別的宣告,依稀記得之前有看過討論,查了一下,這個東西叫做 flexible array member,是 C99 新增的語法,目的是讓動態新增資料更方便﹝語法上﹞,故寫了一個小程式來驗證。

2019/06/10 更新
1. 「C99 6.7.2.1 Structure and union specifiers」提到 flexible array member 只允許在 structure 的最後一個元素,故 UEFI 的 EFI_LOAD_OPTION 應該是用了某種方式達到一個以上的未定義長度的 array,故並不是 standard 裡的 flexible array member。
2. 原文如下:「As a special case, the last element of a structure with more than one named member may
have an incomplete array type; this is called a flexible array member.

#include <stdio.h>
#include <stdlib.h>

typedef struct Item {
    int length;
    // flexible array member
    int data[];
} Item;

int main(void)
{
    // this is decided dynamically.
    int realCount = 4;
    int realSize = realCount * sizeof(int);

    Item *p = (Item*)malloc(sizeof(Item) + realSize);
    p->length = realSize;

    // give values
    for (int i = 0; i < realCount; i++) {
        p->data[i] = i;
    }

    // check size
    printf("sizeof(Item) is %d \n", sizeof(Item));

    // check values
    for (int i = 0; i < realCount; i++) {
        printf("p->data[%d] = %d \n", i, p->data[i]);
    }

    free(p);
    system("pause");
    return 0;
}

執行結果

sizeof(Item) is 4
p->data[0] = 0
p->data[1] = 1
p->data[2] = 2
p->data[3] = 3

UEFI Boot Variable Format - Generic Device Path Node Structure


A Device Path is a series of generic Device Path nodes. The first Device Path node starts at byte offset zero of the Device Path. The next Device Path node starts at the end of the previous Device Path node. Therefore all nodes are byte-packed data structures that may appear on any byte boundary. All code references to device path notes must assume all fields are unaligned. Since every Device Path node contains a length field in a known place, it is possible to traverse Device Path nodes that are of an unknown type. There is no limit to the number, type, or sequence of nodes in a Device Path.


UEFI Application - include path

我們在寫 UEFI Application 時,一般都會放在 "UDKBase\AppPkg" 這個 package 裡面, "AppPkg.dec" 裡面已經很貼心的將 "MdePkg/Include" 加進 "[Includes]" 裡面,所以我們可以直接在 .c 裡面使用 "#include <Library/BaseLib.h>",讓 compiler 可以找到相關的宣告。

換句話說,在找某些不知道的函數時,可以直接來 "MdePkg/Include" 此目錄找,有機會可以找到 UEFI 已經寫好的函數,我們就不用自己寫了。

底下是一些常用到的 header file

#include <Library/UefiLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/PrintLib.h>
#include <Library/BaseLib.h>
#include <Library/DevicePathLib.h>

2019年6月5日 星期三

Code Complete 2 冷知識

之前去天瓏看到這本書,一直以為是作者又出了新版,終於在鬼打牆的查詢後,發現是同一本書,只是變成不同的出版社取得版權翻譯﹝學貫→博碩﹞。回想我當初買書已經是 2008 年的事了,往事真是不堪回首呀。

書名  軟體建構之道   CODE COMPLETE 2中文版: 軟體開發實務指南  
作者 Steve McConnell著; 譚永歸譯   Steve McConnell著; 金戈等譯
出版機構   學貫行銷 博碩文化
出版年月 96/07 107/11
ISBN 9789866800115 9789864341313

沒辦法,翻閱它已經是 10 年前的事了,還知道書架上有這本書就很屌了,想當初我還曾有過《Effective C++: 55 Specific Ways to Improve Your Programs and Designs, 3/e》買了 2 本的記錄XD

僅以此文獻給跟我一樣書太多,一直在懷疑到底是不是新書的人!

Onyx Boox Note Lite 觸控測試備忘記錄

因為手上有四台電子書閱讀器,故每台分配到的使用時間不一,前一陣子在看安納金的書,故都使用 Nova Pro 居多。

昨天在 AlwaysKobo 引起的蝴蝶效應後,撕下貼在 Note Lite 上的保護貼,看完了艾兒莎以及崴爺的書前幾章後,我想我應該是確定了幾件事。

使用藍芽翻頁器沒有問題,那應該跟 Kobo App 無關吧?

買了 Kindle 以外的閱讀器後,感覺變得疑神疑鬼,總覺得出版社電子書有問題,不然就是 App 有問題,再不然就是文石 Android 開放系統調校有問題,這倒是我以前只用 Kindle 沒有想過的事。

目前憑感覺測出左下角綠圈的失敗機率假設是 Z,那紅框處的失敗機率大概就是 3Z ~ 5Z,但此時左上角的綠框卻又一切正常。我不知道觸控式螢幕的原理為何,但總感覺跟系統調校脫不了關係。不知道博閱或是 Hyread 的功力如何,但以我的認知,文石應該是其中的佼佼者吧?

我一定是被第一台電子書閱讀器 Kindle Paperwhite 3 寵壞了!以前看英文技術書都沒這麼多問題,我想這只能等到 Amazon 自己出 Android 開放式閱讀器或是文石將原始碼公開才有機會優化吧,畢竟 Open Source 社群的行動力與廠商不是同一個檔次。

2019年6月2日 星期日

AlwaysKobo 引起的蝴蝶效應

為了參與這次的優惠,選了幾本書,其中一本是艾兒莎的《窮忙世代的翻身準則》,好吧,我承認是先看到妹子封面才買的,但也是因為我對這個主題有興趣,不料卻引發了一連串的蝴蝶效應。

首先,該本書在翻頁時,文字會先莫名其妙的放大,停頓一下才翻頁,看了幾頁後,專注力很難不被打斷,但以我這幾個月的經驗來看,很難說問題是出在誰身上,可能是文石系統、Kobo App,甚至是電子書本身格式都是嫌犯!但我能掌控的也只有文石系統的更新,於是便大膽的更新到 2.1.2,沒想到問題依舊,再加上文石並沒有修復2.1.1 開啟 regal 以及 Google Play Book 閃爍的問題,不禁讓我心灰意冷的上床睡覺。

早上吃完早餐,正想使用久違的冰心訣,繼續跟艾兒莎的書奮戰到底,突然想到何不關掉文石優化選項試試?終於,正直與善良都回來了!

有了這個新發現後,乾脆試試各家 App 關掉文石優化選項會怎樣?感受較明顯的是 EPUB 字似乎變清楚了,翻頁速度似乎也變快了?清晰度感覺是很主觀的事,但速度倒是可以被量測,於是拿出了昨天在迪卡儂購買的碼錶,我才發現我錯怪讀墨了,正確來說是我錯怪各 App 了。

Google Play Book ~ 1.00
Readmoo App ~ 0.98
Kobo App ~ 0.92
Kindle App ~ 1.22

除了 Kindle 翻頁問題,不得不開啟優化選項外,其餘都是關閉優化,與之前量測結果比較來看,著實有不小的差異,我認為目前速度對我來說已經很棒了,足夠讓我沉浸在閱讀的世界中。

可惜的是,我也不能沒有優化選項,不然 PDF 的閱讀體驗在不調整對比下仍然是很糟糕,畢竟我在御三家也購買了一些 PDF,實在無法棄他們不顧,只好視情況使用它了。

既然都做了那麼多測試,乾脆順便驗證 Note Lite 有時點到沒反應的問題,一不做二不休的撕下之前貼的保護貼,費了九牛二虎之力才把它順利取下。

此時回頭想想,原本不是配合 Kobo 優惠才買書的嗎?怎麼又做了一堆驗證測試的事,美好的假期也就此泡湯。