CH552G 怎樣直接輸入中文到 Windows 上的應用程式?
CH552G 作為一款便宜好用的 USB HID 模擬晶片,我當然是想辦法讓他做到各種神奇功能的東西。而其中一個我很有興趣做的就是能直接輸出中文的鍵盤。 可是這樣問題又來了。到底要怎樣才能讓 CH552G 直接輸出中文呢?作為只有 8bit 的 E8051 處理器,根本沒辦法輸出中文不是嗎? 黑魔法:ALT + BIG5 碼 如果有一定年紀的 Windows 使用者,有玩過一些很早期的網絡遊戲的話應該都知道,早期的中文輸入法對各種遊戲和應用程式的支援很差,有時候即使是輸入法能抓到被遊戲 handle 的鍵盤輸入,也不一定能夠輸出字元到遊戲內的輸入框。這個時候就出現了一個神奇的輸入方法,就是在鍵盤上長按 ALT 然後在 keypad 上輸入該中文字對應的 big-5 碼,之後放開 ALT,中文字就出來了!? 然後我又花了幾天把所有 utf-8 跟 big-5 交雜的中文字轉成其對應的輸入用 DEC 碼 當然,在 Windows 10 之後,有不少應用程式(例如 wordpad)都開始轉用萬國碼 UTF-8,但是只要能夠背下兩邊的碼表的話理論上就能夠不透過任何中文輸入法輸入中文了喔? 那麼,我們讓 CH552G 代替我們按鍵盤不就行了嗎? 理論上是這樣沒錯,但是這裡又有一個問題了,就是 Keyboard_press 沒辦法按數字鍵盤啊??? 假設我們要輸入 「你」 好了。它對應的 big-5 和 utf-8 碼分別為 20320 ( 4F60 HEX) 跟 42817 ( A741 HEX),可是當你想著:這很簡單啊,只要 Keyboard_press(KEY_LEFT_CTRL); Keyboard_write("2"); Keyboard_write("0"); Keyboard_write("3"); Keyboard_write("2"); Keyboard_write("0"); Keyboard_release(KEY_LEFT_CTRL); 的時候,它卻輸出了 "20320" 到電腦上。 嗯?為甚麼會這樣? 原來是因為在 USB HID Keyboard 的定義裡面,數字鍵盤的數字跟你英文字上面那排的 hex code 是不一樣的原因。這個時候為了要轉換這堆數字,我寫了這樣的一個轉換 function,把數字的 char 轉換成 keypad 的 hex code (為了找這個我快花了 3 個晚上,累死) char PressNumericAsKeypad(char in){ int delayTime = 1; switch (in) { case '0': Keyboard_press('\352'); delay(delayTime); Keyboard_release('\352'); break; case '1': Keyboard_press('\341'); delay(delayTime); Keyboard_release('\341'); break; case '2': Keyboard_press('\342'); delay(delayTime); Keyboard_release('\342'); break; case '3': Keyboard_press('\343'); delay(delayTime); Keyboard_release('\343'); break; case '4': Keyboard_press('\344'); delay(delayTime); Keyboard_release('\344'); break; case '5': Keyboard_press('\345'); delay(delayTime); Keyboard_release('\345'); break; case '6': Keyboard_press('\346'); delay(delayTime); Keyboard_release('\346'); break; case '7': Keyboard_press('\347'); delay(delayTime); Keyboard_release('\347'); break; case '8': Keyboard_press('\350'); delay(delayTime); Keyboard_release('\350'); break; case '9': Keyboard_press('\351'); delay(delayTime); Keyboard_release('\351'); break; default: return in; break; } } 這樣我們就順利的把數字 char 換成 keypad 輸出的 hex code 了。之後就是再寫一個 wrapper function 把整個輸入中文字的流程更容易開發: //Pass…
ArozOS 的相容性存取模式
在開發 ArozOS 這個計劃的時候,其實大部分的時間我都不是用來寫功能性的東西,而是開發前端,以提升使用者體驗(UX)的東西。從網頁桌面到簡單易用的設定與管理系統,從 FTP 到 WEBDAV 接口等,都是讓不同的用戶及自己能在不同的裝置與環境下使用到自己的伺服器。然而自從 1.0 版 ArozOS 開始開發之後我們一直都還沒有放進去的,就是相容模式了。 新版的硬碟掛載界面 新版的檔案伺服器界面 從 Aroz Online Beta 起相容模式就一直是我們堅持的功能之一。其一是為了一些極端的使用裝置(例如 DSi 的瀏覽器、快譯通之類的嵌入式裝置)可以使用 ArozOS 為資料傳輸用之外,也可以用在一些很惡劣的網絡環境下,讓相容模式變成遠端使用 ArozOS 的最終手段。 AOB 下的相容登入模式 相容模式下只能勉強執行一些簡單的 WebApp 可是 AOB 的相容模式下真的沒辦法做甚麼,除了 Music 跟 Setting 幾個 WebApp 之外幾乎甚麼都沒辦法做(特別是連 File Manager 都開不了這點最讓我覺得奇怪),所以我猜當時開發相容模式就只是為了可以產生伺服器端的 session 然後用同一組 session 來存取伺服器上其他的服務而已。 ArozOS 2.0 的 相容模式 ArozOS 2.0 新加入的 Directory Server 相容存取模式 去到 ArozOS 2.0 之後,相容模式的登入界面也被直接改成有一定年代歷史的 Basic Auth 處理,也把界面盡量減少到只使用最基本的 HTML5 及顯示最基本的虛擬檔案系統層 ArozOS 2.0 的 file system abstraction ,以 compatibility mode 顯示 這樣的設計不但能相容最多的裝置,作業系統等,也能在極為惡劣的網絡環境下(Kbps 速度)存取到你放在伺服器的資料,對於在緊急需要下載個文件之類的還是有點用途(我猜) 如果你有一定年紀的話你會發現這界面好像在哪裡看過。沒錯,這是參考 Apache 的 list dir 界面設計的。簡單、直接的設計怎樣說還是參考前人設計為佳。 Apache 預設的 list dir 界面 結論:實用性有時候比技術重要 現在的前端都太複雜了,不是依靠 Virtual DOM 就是依賴一大堆 HTML5 attribute tags。有時候當你開發的系統是以實用性和高相容性為主的時候,不妨考慮一下以機能而非技術先行,採用 server side 直出 HTML 的做法還比較實際。
ESP8266 讀取 SD 卡太慢?要試試全速 SPI 嗎?
我看到日本技術宅的 Blog ,覺得奇怪這裡為甚麼他可以在 SD.begin 後面設定一個指定的速度(? https://www.mgo-tec.com/blog-entry-esp8266-wroom-spi-speed-up.html 於是我跑去翻 ESP8266 Arduino Core 的源碼,原來 ESP8266 比起原生的 Arduino core 在 SD.begin function call 多了一個可選擇指定的 uint32_t 參數,預設是 SPI 一半速度(4 Mhz),但是如果你的 SD 卡夠快(例如說現在大部分 A1 Class 10 的卡)都可以上到 8Mhz (SPI Full Speed) 或以上(這裡日本部落格用的是 40Mhz,為了資料安全好孩子不要隨便超頻你的 SD 卡) https://github.com/esp8266/Arduino/blob/313b3c07ecccbe6fee24aa9fa447c4aed16ca499/libraries/SD/src/SD.h#L35 嘛不過 ESP8266 的 WiFi 速度極限也就 4Mbps,如果要用來做網頁伺服器的話 SPI 速度設定到全速(8Mhz)已經足夠盡用它的網絡速度了。 備注:如果要設定速度的話可以用 ESP8266 SD library 內預設的常數 uint32_t const SPI_FULL_SPEED = 8000000; uint32_t const SPI_HALF_SPEED = 4000000; uint32_t const SPI_QUARTER_SPEED = 2000000;
在 Raspberry Pi Zero 2W 上設定 WiFi AP 作為 WiFi 中繼器
因為不知道為甚麼網上沒有 Raspberry Pi Zero 2W 以外接 WiFi USB 作為 WiFi 中繼器的教學,所以我就來自己研究出一個方法囉 材料 Raspberry Pi Zero 2WRaspberry Pi OS 用作 wlan1 的 USB WiFi 模組 安裝所需 Package sudo apt-get update sudo apt-get upgrade sudo apt-get install hostapd sudo apt-get install dnsmasq sudo systemctl stop hostapd sudo systemctl stop dnsmasq 設定網絡界面卡 sudo mv /etc/dnsmasq.conf /etc/dnsmasq.conf.orig sudo nano /etc/dnsmasq.conf 寫入以下內容 interface=wlan1 dhcp-range=192.168.0.11,192.168.0.30,255.255.255.0,24h 固定 wlan1 的 IP 地址 sudo nano /etc/network/interfaces 把 source /etc/network/interfaces.d/* 加上 comment: #source /etc/network/interfaces.d/* 寫入以下內容 auto lo iface lo inet loopback auto wlan0 iface wlan0 inet dhcp allow-hotplug wlan1 iface wlan1 inet static address 192.168.0.10 netmask 255.255.255.0 broadcast 192.168.0.255 gateway 192.168.0.254 設定 Hostapd sudo nano /etc/hostapd/hostapd.conf 寫入以下內容(記得更新 WiFi 名稱與密碼) interface=wlan1 hw_mode=g channel=7 wmm_enabled=0 macaddr_acl=0 auth_algs=1 ignore_broadcast_ssid=0 wpa=2 wpa_key_mgmt=WPA-PSK wpa_pairwise=TKIP rsn_pairwise=CCMP ssid=[WiFi SSID 名稱] wpa_passphrase=[WIFI 密碼] 之後編輯預設設定 sudo nano /etc/default/hostapd 把原本的 #DAEMON_CONF="" 改成 DAEMON_CONF="/etc/hostapd/hostapd.conf" 設定 wlan1 -> wlan0 的 forwarding sudo nano /etc/sysctl.conf 把 #net.ipv4.ip_forward=1 改成 net.ipv4.ip_forward=1 新增 iptables 規則 如果你是用 Lite 版沒有 iptables 可以先透過以下指令安裝 sudo apt-get install iptables 然後輸入 sudo iptables -t nat -A POSTROUTING -o wlan1 -j MASQUERADE sudo sh -c "iptables-save > /etc/iptables.ipv4.nat" 編輯 rc.local 在啟動時自動應用規則 sudo nano…
Arduino 用在產品上太貴?有聽過 CH552G 嗎?
話說一個月前我在想到底有甚麼方法可以替 Raspberry Pi 增加一個 Analog Read 的功能,看了網上很多的教學和文章,大致上的方法就只有 用 ADC 透過 SPI 傳到 Raspberry Pi 的 GPIO用 USB 接一片 Arduino UNO 再透過 Serial 傳送讀取的資料 可是 ADC 需要接到 Raspberry Pi 的 3.3V GPIO,用來量 5V 的 Analog 電壓的話總覺得有點危險,要安全的話要加一片 LLC (Logic Level Converter,5V 轉 3.3V 的),需要的空間又會變更多,而且生產上來也不會特別便宜。 另外第二個方法比較安全(畢竟 USB 的 5V 是直接來自電供的,如果有短路電供會先斷開作保護),但是一片 Arduino (ATmega328)價格一點都不便宜,即使用較便宜的 ATtiny 44 也需要快 10 - 12 港幣一片,如果真的要量產起來一點都不比 ADC + LLC 便宜。 然後剛好我在研究 CH340 的各種版本時,在那間公司的網站不但發現到有一種 CH340 有內置晶振(不用外接,省掉焊接和零件的成本)而且還發現了一種新的 MCU 沒錯,這就是今天的主題:CH552G 於是我便隨便買來了一片開發板,來到之後長這樣,真的好小,跟我前女友的現任男友 ㄐㄐ 差不多大小。 CH552G 的好處在於以下幾點 內置 USB HID 控制器,不需要外接 USB to Serial 轉接晶片(如 CH340)5V Logic Level,可測電壓為 0 - 5v (對應 0 - 255,共 8bit 準確度)超級的便宜,大概 5.5 港幣就能買到一片(開發板也只是約 15 港幣一片) 使用 Arduino IDE 對它進行編程 https://github.com/DeqingSun/ch55xduino 上面是這次使用的 Arduino board definition。跟其他的第三方板子一樣,先把它給的 json 檔加入你的 Arduino 設定裡,再在 broad manager 找到 ch5xx 的板子把它加進去。 https://raw.githubusercontent.com/DeqingSun/ch55xduino/ch55xduino/package_ch55xduino_mcs51_index.json 對於全新的開發板,第一件事情就是先安裝 bootloader。詳情教學可以看 Github,但是對於 Windows 用戶在跟著 Github 教學前需要先為 CH552G 安裝 driver,不然在 Windows 內會顯示為不明裝置。其步驟為下: 下載 Zadig ,https://zadig.akeo.ie/按著在沒插電的開發板上的 PROG 按鈕(或「下載」按鈕)把開發板透過 USB 線連到電腦(注:不能鬆開按鈕)等待開發板在「裝置管理員」以「不明裝置」顯示之後才可鬆開打開 Zadig,點選 Unknown Device 1,選擇 Install Driver第 3 - 5 分鐘(可能更慢,看電腦規格)完成之後把開發板拔出,再重新插回去電腦裝置管理員會顯示為 COMX (我的話就是 COM7) 完成後的 Zadig 界面 安裝完 driver 的開發板,COM7 燒錄 Bootloader 在開發板寫程式的時候 bootloader 會順便送進去,所以這裡我們先要選好正確的板子(我這片是 CH552) Pin 的編號就是以開發板上寫的 x10 為準,例如說要控制 P3.0,pin number 則輸入 30,P3.2 則是 32 如此類推。因為我要順便測試 analogRead 跟 USB Serial,所以我把 blink 改成這樣 int val = 0;…
使用 Apache2 當 Reverse Proxy 伺服器
因為最近房東在沒經我同意之前在房間的網絡上遊加入了一台 NAT 路由器,所以原本架在我的房間裡的 ArozOS 伺服器就沒辦法在外面連線了。想了想,於是我想到了可以透過 zeroTier 和 Reverse Proxy 來使用我房間裡的伺服器,所以便開始研究怎樣可以弄到一台 Reverse Proxy 的伺服器。 網絡上很多人喜歡用 nginx 來當 RP伺服器,可是基於某些原因我並沒有太喜歡它所以我就選擇用 Apache2 了。首先,安裝 apache2 sudo apt-get update sudo apt-get install apache2 -y 然後就是編輯它的設定檔,加入你需要 proxy 的目標 sudo nano /etc/apache2/sites-available/000-default.conf NameVirtualHost *:80 <VirtualHost *:80> ServerName ixtw.hkwtc.com ProxyPass / http://{zerotier 的區網 ip}:8080/ ProxyPassReverse / http://{zerotier 的區網 ip}:8080/ </VirtualHost> <VirtualHost *:80> DocumentRoot /var/www/html </VirtualHost> 然後 Enable Proxy 插件並重啟 apache 2 sudo a2enmod proxy_http sudo systemctl restart apache2 可是,WebSocket 要求過不去欸? 這是因為要 proxy websocket 會需要額外的 module 去處理,首先啟用 wstunnel 跟 rewrite engine sudo a2enmod proxy_wstunnel sudo a2enmod rewrite sudo systemctl restart apache2 然後加入 RewriteCond 跟 RewriteRule <VirtualHost *:80> ServerName ixtw.hkwtc.org RewriteEngine On RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC,OR] RewriteCond %{HTTP:CONNECTION} ^Upgrade$ [NC] RewriteRule /(.*) ws://192.168.196.15:8082/$1 [P,QSA,L] ProxyPass / http://192.168.196.15:8082/ ProxyPassReverse / http://192.168.196.15:8082/ </VirtualHost> 最後再重啟一次 apache sudo systemctl restart apache2 這樣就完成了!
透過 Arduino 取得 UART HMI 螢幕頁面 ID 然後按需求轉頁
最近因為我在弄一個 60W 的 PD 充電器,然後想弄一個迷你的螢幕來顯示電池的資訊,所以我便選用了一個 2.2寸的 UART HMI 了。 2.2 寸的 UART HMI,比想像中要小一點 選 UART HMI 的原因有很多,網上也有很多文章教你怎樣選合適的螢幕,所以我就不細說了。簡單來說, UART HMI 是一種可以透過 Serial 來控制螢幕載入預先設計好的界面的一種人機界面。 發送指令到螢幕 HMISerial 是 Software Serial。以下 function 把 cmd 內的內容發到螢幕,如果 debugMode 被啟用,側會同步輸出到 hardware serial 上。 SoftwareSerial HMISerial(2, 3); // RX, TX //... void sendCommand(String cmd){ if (debugMode){ //Mirror output to serial Serial.print(cmd); Serial.write(0XFF); Serial.write(0XFF); Serial.write(0XFF); } HMISerial.print(cmd); HMISerial.write(0XFF); HMISerial.write(0XFF); HMISerial.write(0XFF); delay(50); } 使用例子: sendCommand("t0.txt=\"[info] MCU Connected\""); 取得現在 HMI 屏幕正在顯示的 Page ID 如果你把 sendme 指令發到屏幕,屏幕會回傳現在的 page ID 給你,它的回傳信號大約長這樣 66 01 FF FF FF 66 是這個指令的回傳碼,01 是現在的 page ID (即是 page 1),FF FF FF 側是傳送完成的意思,所以我們只需要在 Serial.read() 的時候抓到 0x66 就知道下一個一定是 page ID 了。 int getPageNumber(){ sendCommand("sendme"); bool nextReadIsPageNumber = false; while (HMISerial.available() > 0) { // read the incoming byte: incomingByte = HMISerial.read(); if (nextReadIsPageNumber){ //這是 page ID nextReadIsPageNumber = false; return incomingByte; } if (incomingByte == 0x66){ //下一個出現的 byte 就是 page ID 了 nextReadIsPageNumber = true; } } } 使用例子(檢查現在是否在 page 0(hex: 0x00)) currentPageNumber = getPageNumber(); if (currentPageNumber == 0x00){ //Do something } 成果(Arduino 透過 COM port 輸入到模擬器)
ArOZ Portable 主板開發計劃
說到 ArOZ Portable 計劃,這是一台可以放進口袋裡的迷你 ArozOS 伺服器。如果你沒看過的話現在的版本大約長這樣 最穩定版本的設計 可是如果你有機會把它拆開來看,你就會發現這版本其實是沒辦法量產的。因為裡面的線路長這樣 所以結論是:在真的量產之前我要先把它變成可以量產的設計。 ArOZ Portable 主板 通常說到電腦、手提電子裝置等等的東西第一個最基本的東西就是主板了。 這個計劃由 2016 年開始我就不斷在嘗試弄一塊主板來省略那堆亂七八糟的走線,可是每次都因為不同的原因而失敗。最大的原因可能是因為我還沒有焊接 小於 SOP 跟 0805 針腳的技術力吧,也有不少原因是當年的畫板技術還沒足夠讓我真的去自由發揮。 在這裡我就跟大家分享一下這幾年來我設計的 ArOZ Portable 主板(失敗品)吧 初代 ArOZ Portable 主板 第一代的 ArOZ Portable 主板 這一塊主板基本上就是一塊 FE1.1S USB Hub 晶片 + Micro SD 轉 USB 的晶片(用以代替外接的 USB 儲存裝置),但是當然這兩塊晶片的腳位都是 SSOP 的,而到現在我還是沒有合適的工具去焊接 SSOP 腳位,所以這板子當然是失敗了。 第二代主板 第二代的主板主要是把 SD 卡讀卡器移除,跟把充電電路放回進去。你在 U2 的位置能夠看到一個熟悉的 TP4056 layout,理論上是可以提供 5V 1A 的充電性能。但是唯一一個問題是這電路設計的時候沒考慮到 5V 升壓問題(而且還要畫完,在掉去生產前一刻才發現這問題),而大部分 USB 裝置必須要有 5V 供電才能運作,結果這板子也是不能用的。 第三代主板 在發現第二代這種低級錯誤之後第三代就換回去用移充的主板來供電了(右上的那個凹進去的位置),然後順便加粗了供電的走線和買了焊膏和熱風槍。雖然有成功焊出一兩塊,但是最後也是因為 FE1.1S 焊的良率太低而報廢(果然還是需要紅外線焗爐啊) 第四代 想著既然第三代都能有幾個 % 的成功率,那第四代也能碰碰運氣看看定 20塊板子有沒有一塊能成功吧?於是我把充電、升壓、USB Hub 等等全部放到一塊板子上面,結果良率太低全部焊完之後一塊正常運作的板子都沒有(# 第五代 「算了,還是 back to basic 好了。」用這種邏輯而畫的版子。只提供了最基本的電源、USB port 信號 routing 跟 USB Hub 的晶片,結果雖然有一點問題,但是加一點 patch wire 之後總比一大堆線要好。可是這體積,應該還能再小一點? 第六代 因為考慮到能不能把良率超低的 FE1.1S 找 OEM 進行焊接,然後以模組的形式插回到主板上而開發的板子。基本上與第五代的設計一樣,就是把 FE1.1S 的 footprint 換成了 2.54 針腳的插槽 可是後來這版本並沒有進行生產,因為問了才知道這麼少的生產量走一趟 OEM 貼片實在太貴了(比起買 USB hub 模組回來拆還要貴),所以就這樣這東西就放置了 1年多(由 fyp 開始到 grad 我都沒碰過這計劃) 第七代 在香港疫情爆得最厲害的時候因為在家裡沒事幹所以抽了點時間來設計這塊板子。這基本上是基於第七代的設計,但是把多餘的板子部分切走,讓它最小化方便安裝。可是沒進行生產的原因也是跟第七代一樣。另外你也能看到背面原本要放移充主板的位置被一塊 Powermanv5 代替。 主板背面,使用自家開發的 Powermanv5r2 主板代替移充主板,這樣就不用每做一台 ArOZ Portable 就犧牲一塊移充 背面用來供電跟充電的 Powermanv5r2,也是自家開發的其中一種通用模組,已經量產 https://www.tindie.com/products/tobychui/powerman-power-boost-lipo-charger-inoutput-5v-2a/ 第八代 經過這一年來不斷來回生產不同的 PCB 來做 STEM Kit 跟 了解了更多不同類型的晶片供應商,現在終於有技術可以重新回到這個 project 了。在幾個巧合的情況下才讓我有辦法設計到這塊板子: 在 twitter 看到有工程師分享一塊 SOP16 的 USB Hub 晶片:SL2.1A在拆移充時發現了一塊更便宜的充放管理晶片:HT4928我已經開發好 Powerman 跟 Powerloli 兩塊通用鋰電池充放管理板(內置升壓功能)終於理解 When in doubt, ground it out (有懷疑不知道它要連哪裡的時候,就把它接地吧)的道理 後面可以直接拉線到 Raspberry Pi Zero W 的 test pad 供電和 USB 接口 然後就是等 Power Loli v2 的樣品 PCB 回來,測試過沒問題之後就可以正式生產這塊第 八代的板子了。 8 May…
Sinilink XY-WF5V 灌 Home Dynamic v2 IoT 控制器
最近因為一些原因拿到了兩塊 Sinilink 的 XY-WF5V WiFi 繼電器模組。由於它的內置 firmware WiFi 有鎖,加上它的 App 看上去就覺得很爛,所以我決寫把它的 firmware 刷掉重新寫一個 HDSv2 的 firmware 進去,讓我的雲端 IoT 控制器能夠控制到它。 首先,怎樣在非開發板上灌程式? 這個時候你就需要 USB 編程器了(大陸叫下載器,通常我叫它 ISP),你可以用不同的方式來灌程式進去,可是我這裡用的是最便宜的 ESP01 用編程器,樣子大約長這樣 然後我們就可以直接把線從那個 2 x 8 2.54 母頭裡拉出來,直接焊接在 ESP8266 上面,線路如下 接線圖 完成之後大約長這樣 逆向工程 之後就是把板子的線路重新畫出來。由於這是一塊兩層板,所以沒甚麼大問題。之後再把找到的 GPIO 跟據需要重新寫進 HDSv2 On/Off 的 example sketch 裡面, 可是,我們怎知道應該使用哪一塊開發板的配置呢? 這個我們可以選擇使用 Wemos D1 R1 作為基礎,重新把 ESP8266 上對應的針腳在 Wemos D1 上找到對應的 Digital Pin 號碼即可。完成之後 Arduino sketch 裡面的開關 pin 被改成如下: int signalOutputPin = D14; //The pin to activate the mosfet of relay int buttonPin = D6; int refPin = D8; 如果找不到 Pull up / down 電阻怎辦? 另外,如果你在板子上找到沒有 pull up / pull down 的按鈕,很有可能它是使用軟體方式做的 internal pull up / down 電阻。在更改 HDSv2 的 example 時只要把 INPUT pin 的設定由 INPUT 改成 INPUT_PULLUP 即可,例子如下: pinMode(buttonPin, INPUT_PULLUP); 相關可以使用程式 pull up / down 的針腳可以參考下表(請對應 Generic 8266 的 GPIO 號碼,不要使用最左欄的 pin 號碼) 完成圖 完成之後在 ArozOS 內重新掃描一下 IoT 裝置,應該就會有新的 Sinilink WiFi Relay 在列表中出現了。
用了三年時間寫網頁桌面作業系統的故事
這是一個想找地方儲存他的音樂、影片跟圖片的窮學生與他的 Raspberry Pi 的故事。 如果你想直接下載來玩,這裡是傳送門:https://github.com/tobychui/arozos 開始時候的樣子 由 2016 年開始,我就一直在寫這套自用的系統。這系統主要是用來存放音樂、影片檔案等等的媒體文件,這樣我就可以很方便的在課堂跟課堂之間的休息時間聽到自己的音樂或是看一套短劇。這是這套系統於 2016 年的時候的樣子 這個版本是使用 PHP5 開發,後來升級到了 PHP 7 + Apache 伺服器。雖然同一台主機(當時我還是在用我的主機來當伺服器)上面有安裝到資料庫,但是它本身是不需要連接到 MySQL 資料庫的。這系統基本上是使用膠水語言黏起來的,運作原理就是後台的一個 VB.net 程式定時把硬碟上的音樂檔案掃描,並產生一個音樂列表讓 php 去 render 一個網頁界面。當有需要的時候再從硬碟裡搬出來到網頁伺服器的資料夾再進行串流。 你現在依然能夠在我的 Github 找到最原始版本的 ArOZ Online 系統(後來才改名為 ArozOS 作業系統),但是拜托 不!要!用!它!https://github.com/tobychui/ArOZ-Omega-Online 由 PHP 到 Go:開發難度與效能的平衡 這個非常簡單的 PHP 版本使用一兩年之後,因為我開始在上面放越來越多的檔案,單一頁面已經無法應付所有檔案的列表,所以開始加入檔案管理器、模組化的播放器到最後的網頁桌面 不過兩年後,PHP 的系統還是無法應付很多大型檔案(特別是現在的檔案都越長越大,由以前幾 MB 的 mp3 到現在隨時到 50 - 60MB 的 flac 檔案),加上桌面系統做得越來越像本地端的桌面,而需要大量而且高反應速度的資料回傳,因此 PHP 已經沒辦法再成為這系統的主力語言,而需要轉移到另一種語言繼續開發。有興趣了解更多關於這部分的技術問題可以看這篇: http://imuslab.com/wordpress/2020/03/29/%E7%B7%A8%E7%A8%8B%E8%AA%9E%E8%A8%80%E7%9A%84%E6%A5%B5%E9%99%90%EF%BC%9Aphp/ 最後經過一點研究之後,我決定轉移到 Go 語言,並把 ArOZ Online Beta (AOB)正名為 ArozOS 。 3 年後的 ArozOS 系統 經過 3 年的開發,它終於成為了一個類本地作業系統的網頁系統。首先就讓我們由桌面開始介紹吧! 網頁桌面 ArozOS 的桌面基本上就是 Ubuntu 20.04 混 Windows 的風格。你可以看到類似 Ubuntu GNOME 的通知欄 也能夠在右上角看到電源開關(可以透過啟動參數關閉這功能),還有一些方便的捷徑 就像 Windows 一樣,如果你要建立一個新檔案也只需要右鍵即可。你也可以透過右鍵選單來更改桌面背景 開始功能表也是如此,看著有沒有一點熟悉的感覺? 在結束桌面的介紹之前最後一定要說的:桌面版的重新命名界面! 看到沒有彈出視窗的感覺是不是非常有桌面的感覺呢?是不是有那種回到家對著主機螢幕的那種安心感(不對 檔案管理員 在使用原本的系統一段時間之後,我開始需要上載其他東西到我的系統裡。而最通用的界面去查看不同類型的檔案當然是?沒錯,就是檔案管理員。所以我就自己寫了一個進去我的系統啦 我的檔案管理員有兩種模式,為別是「列表」模式跟「縮圖」模式 在縮圖模式下,檔案管理只會嘗試從檔案中提取預覽圖片。這功能適用於音樂、影片,照片甚至 3D 模型檔案 檔案管理員最初並沒有分類和排序的功能。可是由於上載到系統的檔案數目日益增加,所以去到一個地步我還是需要把排序功能加進去才有辦法找到我的檔案( 之後還加入了支援 regex 的檔案尋找功能 噢,如果你是喜歡 dark theme 的使用者,檔案管理員也提供 dark theme 模式,不過這最初只是方便我在晚上找電影來看而已 檔案管理功能 檔案管理員提供很多不同的檔案功能。你可以在右鍵選單中找到所有的功能。 就如作業系統一樣,你也可以選擇以某一個 WebApp 開啟指定的檔案 為了讓自己在收拾和清理資料夾的時候比較方便,所以系統也加入了支援 drag & drop (拖放)的功能。要移動檔案的時候只要很簡單的把檔案由一個視窗拖放到另一個視窗即可。 由於 Golang 本身提供 async 模式以處理要求(request),因此這樣的功能比起 PHP 更容易開發。這個即時的進度顯示是使用 websocket 技術,讓後端一邊複制檔案一邊回傳進度。 檔案分享 間中我也會有需要透過 ArozOS 分享檔案的功能。因此我就順便把這個功能加進去了。 (這裡只是一個例子,乖孩子不要把 localhost 的網址分享給別人喔) 別人就可以透過 QR Code 或是分享的連接來下載到檔案 回到原點:音樂與影片播放 當然這些功能現在還存在吧!經過三年的開發,這些功能已經比之前的好用很多了。使用 PWA 技術,現在的音樂播放器大約長這樣 這個界面甚至可以在 Android 手機上顯示獨立的播放界面(如果你是工程師,這個叫 MediaSession API) 影片播放模組亦是如此。使用 HTML5 技術,它能夠串流影片和電影,不再需要好像以前的版本那樣先下載才能看了。 系統設定 基本設定 由於這套系統已經長這麼大,這麼複雜了,要管理這套系統亦會需要一個很複雜的設定界面。我嘗試把設定界面做得簡單易用,所以就設計了一個分類,讓不同的設定放在不同的子分類裡,然後下面再有不同功能設定的細分類。 首先,你可以在系統設定看到系統的基本資料與處理器、記憶體使用量。 WebApp (網頁應用程式)及 Subservice (子服務) 當然,作為一個網頁桌面系統,當然也需要一個安裝應用的界面吧?所以我就弄了一套應用系統出來了。以下是一堆我寫出來自用的應用程式 WebApp 都是一些簡單,只需要檔案存取的應用程式。這些 WebApp 使用 JavaScript 編寫,並使用 Otto VM 作沙盒隔離。而 Subservice 則是一些比較複雜,需要直接與 OS 連接的程式。 你可以輕易的透過設定界面安裝和移除 WebApp 可是 Subservice 只能設定啟用和禁用。畢竟有一些 subservice 是跟系統運作穩定性相關的,理論上應該是由裝置的…
目前第 2 頁,共有 6 頁