將 Windows 10 PC 變成 iBeacon:使用 windows-rs 實作

這幾天在練習使用 windows-rs,寫了一個讓 Windows 10 廣播 iBeacon 訊號的小程式。

完整的程式碼:https://github.com/riddleling/beacon-publisher-on-windows

這個程式很簡單, 使用 UWP API 的 BluetoothLEAdvertisementPublisher 發布 iBeacon 廣告:

let manufacturer_data = BluetoothLEManufacturerData::new()?;

// 設定 iBeacon 的 Manufacturer Data:
manufacturer_data.SetCompanyId(0x004C)?;  // Company ID
let data:[u8; 23] = [
    // Type:
    0x02,
    // Data Length:
    0x15,
    // Proximity UUID:
    0xE3, 0x0A, 0xC8, 0xFE,
    0x75, 0xB8, 0x47, 0x21,
    0x4B, 0x5D, 0x56, 0xB7, 
    0x07, 0x64, 0x25, 0xA9,
    // Major:
    0x00, 0x02,
    // Minor:
    0x00, 0x03,
    // TX Power:
    0xC8
];

let writer = DataWriter::new()?;
writer.WriteBytes(&data)?;

let buffer = writer.DetachBuffer()?;
manufacturer_data.SetData(buffer)?;

let publisher = BluetoothLEAdvertisementPublisher::new()?;

// 把 Manufacturer Data 加入 publisher:
publisher.Advertisement()?.ManufacturerData()?.Append(manufacturer_data)?;

// 開始廣播:
publisher.Start()?;

停止廣播:

publisher.Stop()?;

寫了一個 Serial Port Tool

最近用 Rust 寫了一個 serial port tool 給自己用,GUI 的部分使用 gtk-rs, serial port 通訊的部分使用 tokio-serial (serialport-rs 的 tokio 運行時版本),USB hotplug 的部分使用 rusb (libusb 的 Rust 包裝)。

不過,因為 libusb 不支持 Windows 上的 hotplug,所以在 Windows 上執行時,我使用一個 loop 每隔一秒列舉一次 USB 裝置,來判斷是否有 USB 裝置插入或拔出。

Serial Port Tool 的原始碼:https://github.com/riddleling/serial-tool

然後可以用 Arduino 寫一個 serial echo 程式來測試,把寫入 serial port 的字元回傳回來:

// Arduino serial echo

void setup() {
    Serial.begin(115200);
}

void loop() {    
    if (Serial.available() > 0) {
        Serial.print((char)Serial.read());
    }
}

在 Linux (Raspberry Pi OS) 上執行 serial port tool 的畫面:

在 Windows 上執行的 demo 影片 (透過 serial port 傳輸指令,打開或關閉 LED):

用 Raspberry Pi 打造一台 Spotify 播放器 – Part 2

延續上一篇的內容,要接著說明控制端的 GUI app 如何編譯執行。

在開始之前,先用 ssh 連到 Raspberry Pi,然後安裝 mDNS 的套件包與修改主機名稱。

$ ssh pi@<Raspberry Pi's IP address>
$ sudo apt -y install avahi-daemon
$ sudo raspi-config

執行 sudo raspi-config 後,會看到一個文字介面的選單,選擇 System Options => Hostname,然後把 Hostname 改成 spotifypi (或是你喜歡的名字)。改完後請重新開幾。


Raspberry Pi 開啟 mDNS 的服務後,我們就可以透過 <hostname>.local 這個網址來取代 IP 位址,例如:假設 Raspberry Pi 的 IP 位址是 192.168.1.110,那我們透過 WebSocket 去控制時的 URL 是 ws://192.168.1.110:9487,現在有了 mDNS,可以把 URL 改成 ws://spotifypi.local:9487。

不過,如果控制端的電腦不是 macOS (macOS 內建 mDNS 的支持),那還需要安裝一些軟體。在 Linux 上,需要安裝 avahi。Windows 則比較麻煩,以前在 Windows 上安裝 Apple 的 Bonjour Print Services 就可以開始用 mDNS,後來在某次的 Windows 10 更新後, Bonjour 就不能用了,還需要修改 Windows 登錄機碼才行,有興趣的人可以參考這裡


開始來說明控制端的 GUI app。我這個 app 是用 Rust 寫的,GUI 的部分使用 gtk-rs,WebSocket 的部分使用 tokio-tungstenite。

編譯之前需要先設定開發環境,首先,先安裝 rustup。然後需要安裝 GTK 3 的開發套件包。

在 macOS 上安裝 GTK 3 的開發套件包:

$ brew install gtk+3
$ brew install gnome-icon-theme

在 Debian / Ubuntu 上安裝 GTK 3 的開發套件包:

$ sudo apt install libgtk-3-dev build-essential

在 Windows 上安裝 GTK 3 的開發環境:請參考這篇


下載控制端 GUI app 的程式碼,並且編譯:

$ git clone https://github.com/wlelab/SpotifyPi-Control-Panel.git
$ cd SpotifyPi-Control-Panel
$ cargo build --release

編譯需要一段時間。編譯完成後,執行檔會放在 SpotifyPi-Control-Panel/target/release 目錄下。

在 Windows 上,直接執行 SpotifyPi-Control-Panel\target\release 目錄下的 spotifypi-control-panel.exe 即可,在 Linux / macOS 上,可以透過終端機執行:

$ ./target/release/spotifypi-control-panel

Windows 上的執行畫面:

Demo 影片:

用 Raspberry Pi 打造一台 Spotify 播放器 – Part 1

最近把 Raspberry Pi 4B 改成 Spotify 播放器,想把製作方式記錄下來。

以前要在 Raspberry Pi OS 的 Chromium 上執行 Spotify Web Player,會因為缺少 Widevine DRM 支持的關係而無法播放。約在今年三月時,Raspberry Pi OS 正式提供了 Widevine DRM 的支持,所以現在只要在 Raspberry Pi OS 上安裝 Widevine DRM 的套件包即可用 Chromium 播放 Spotify!

在 Raspberry Pi OS 上開啟終端機,執行:

$ sudo apt update
$ sudo apt upgrade
$ sudo apt install libwidevinecdm0
$ sudo reboot

然後用 Chromium 打開 https://open.spotify.com,就可以開始使用 Spotify 了。


不過我想把 Raspberry Pi 改成 Spotify 專屬播放機,所以接下來就來說明如何設定吧。

閱讀全文

筆記》Windows 安裝 gtk-rs 開發環境

步驟 1:安裝 rustup

步驟 2:安裝 MSYS2

步驟 3:開啟一個「MSYS2 MSYS」shell:

更新套件包與資料庫:

$ pacman -Syu

更新套件包 :

$ pacman -Su

安裝 GCC toolchain:

$ pacman -S --needed base-devel mingw-w64-x86_64-toolchain

安裝 GTK 3:

$ pacman -S mingw-w64-x86_64-gtk3

步驟 4:編輯 Windows 環境變數:

  • 在使用者變數的 Path 裡加入:C:\msys64\mingw64\bin
  • 在使用者變數新增一個 GTK_LIB_DIR 變數,變數值為:C:\msys64\mingw64\lib
  • 修改完環境變數後,將 Windows 重新啟動。

步驟 5:開啟一個 Windows Terminal 或是 PowerShell:

輸入以下指令添加 target:

PS C:\> rustup target add x86_64-pc-windows-gnu

然後輸入「rustup show」指令查看 target,應該可以看到這兩行:

stable-x86_64-pc-windows-gnu
stable-x86_64-pc-windows-msvc (default)

接著輸入下列指令,把預設的 toolchain 改成 GNU:

PS C:\> rustup default stable-x86_64-pc-windows-gnu

步驟 6:使用 cargo 指令建立一個新專案:

PS C:\> cargo new my-gtk-app
PS C:\> cd my-gtk-app

然後在 Cargo.toml 的 dependencies 裡加入 gtk:

[dependencies]
gtk = "0.14.3"

編譯執行,看看有沒有錯誤訊息:

PS C:\> cargo run

讀書》A Tour of C++ 中文版

《A Tour of C++, 2/e》繁體中文版與簡體中文版

最近把《A Tour of C++, 2/e》中文版重讀了一次,上次讀的時候因為台灣譯本裡的一些翻譯名詞看不太懂(有些名詞既不是台灣傳統上的譯法,也不是中國那邊的譯法),所以最後也沒讀完就丟在一旁了。

最近開始想認真學習一下 Modern C++(因為想用 JUCE 寫跨平台程式 🙂),所以把《A Tour of C++, 2/e》繁體中文版又拿出來讀,並且另外買了簡體中文版,當繁體版看不懂時就翻簡體版來對照著看 XD

《A Tour of C++, 2/e》內容涵蓋了部分 C++20 特性,而且很薄(才兩百多頁),很適合拿來快速理解 Modern C++…(大誤)。嗯,對有 C++98 經驗的人來說,這本應該是不錯的現代 C++ 入門書,對沒什麼程式經驗的人來說,這本書恐怕不易消化 😅(其實我覺得 Bjarne Stroustrup 的書對新手來說都不算友善 XD,個人感想,勿戰)。

談 C++ 語言的書通常都很厚,光是看到那比磚頭還厚的厚度,就沒什麼動力讀下去,這本《A Tour of C++, 2/e》夠薄,拿來入門剛剛好。不過,我認為最好的 C++ 入門書還是《Essential C++》,薄薄一本只有兩百多頁,講述了 C++ 最基本最核心的部分,只可惜《Essential C++》是 1999 年出版的,內容對現在而言已經過時了…

說到《Essential C++》,讓我想到了 Stanley B. Lippman 在《Essential C++》前言裡提到他在迪士尼電影動畫公司工作時,有次被要求用 Perl 重寫一個工具程式,但他不懂 Perl,所以他想找一本 Perl 書籍來抱佛腳,而且那本書不能太厚,因為當時的情況需要快點讓那個 Perl 程式動起來,最後他找了《Learning Perl》(台灣譯本名為:《Perl 學習手冊》)來讀。這次的經驗讓他明白對於想立刻學會並使用 C++ 的人來說,《C++ Primer》過於龐大複雜了,因此他寫了《Essential C++》這本小書。

說到《Learning Perl》,又讓我想起我的第一份正職程式設計工作時的一件事 😅,當時我剛進去工作不到兩個禮拜,第一個任務是要把一本英文字典做成 iOS app,當時的老闆已經有寫好一支程式把字典的純文字檔轉換成他想要的特定格式,他讓我接手修改那支程式,那支程式是用 Objective-C 寫的,我當時研究了程式的內容與特定格式的結構後,發現那支程式的效果不好,因為還需要半人工的方式去修改文字檔,而且無法正確找出所有的格式問題,最後我決定重寫一支程式來處理格式的問題。

一開始我是用 Objective-C 去寫,寫了一堆 NSRegularExpression 😵,過了三個禮拜後,覺得寫 NSRegularExpression 實在太痛苦,而且寫到卡關了,所以決定改用 Perl 來處理格式問題。雖然之前有用 Perl 寫過一些小程式的經驗,但是當時有一陣子沒寫 Perl 了,已經忘光 Perl 怎麼寫,因此趕快重讀了《Perl 學習手冊》(忘記是第五版還是第六版了),用了約四、五天的時間讀了一遍《Perl 學習手冊》,然後開始寫 Perl script 來處理格式問題,後來寫了十幾支 Perl script 才終於解決完格式的問題(一支 script 處理一種格式問題),而且才花了一個多禮拜的時間 😁

雖然格式的問題解決了,但是我後來發現文字檔裡有少數的地方有亂碼(原本的字典純文字檔就有亂碼),結果最後還是得找工讀生拿紙本字典對照著文字檔找出所有的亂碼,並手動修正,噗,這樣一開始就請工讀生直接手動修改格式並修正亂碼不就得了 🙃 …… #這就是人蔘啊

好像越扯越遠了,今天先這樣囉,Bye~