Development Logs
Prototype built updates and some Q&A of a certain prototype can be found here.
WebStick – 基於 ESP8266 的網頁伺服器棒棒
自從我看了 ESP8266 的 SD Web Server Youtube 教學之後,我一直都很想要自己做一個來玩玩看。你想想看,有一根可以隨身攜帶(?)、足夠便宜到可以送人而且能夠把虛擬的東西(網站)實體化,不是一件很有趣的事情嗎? 可是之前一直都沒有時間研究這個東西,其中一個原因是以前的焊接技術還沒足夠讓我可以直的完成這個 project,另外就是因為那個時候我對燒錄器設計還是沒有甚麼概念,導致到當我要做到跟一片 Wemos D1 mini 同等效能的 ESP8266 的時候,完全沒辦法好好的設計和焊接成成品出來。 開坑 早在 2018 年,我就已經買來了一片 Wemos D1 mini 跟超級難買的 SD shield 來當小型網頁伺服器。當時的我對網頁編程和嵌入式開發還是非常的入門,結果做出來的東西就是長這樣 Wemos D1 + SD Shield + 小容量 SD 卡 雖然是能用,而且我也把它用 USB 供電吊在我的桌面旁邊當作實驗品開發了一段時間,但是由於用的是別人的 code 加上當時我並不是太熟悉 Arduino C++ (和當時還沒有 ChatGPT),導致最後開發出來的東西不但不好看而且很難用 設計嘗試,失敗收場 之後一年我試著把這個設計弄成一片真正的電路板。由於當時我還沒有開發燒錄器的能力(特別是要想辦燒焊那兩個超小的 BC817 transistor),因此我的想法是先把 ESP8266 焊到板子上,再透過現成的燒錄器對它進行開發(見下面那一排燒錄用排針),然而後來我弄著弄著就覺得不對勁,而且這種每次都要插燒錄器才能寫東西的系統感覺開發起來就很麻煩,應該不會有人想用,所以最後還是沒拿來生產。 第一代的 ESP8266 網頁伺服器,最後沒做生產真是一個明智的決定 5 年之後,我終於做出了 WebStick 原型機 WebStick 這東西其實在我腦海中已經卡住很多年了。但是一直就軟硬體技術原因無法開坑。直到最近開始學會了 drag soldering 跟找到了一款可以讓我進行超精密焊接(但是缺點是一次性)的烙鐵頭後,我終於把這個封塵多年的 project 重新抓出來做。 首先:燒錄器 網上有很多不同的設計,有自動的也有半自動(燒錄的時候要按 FLASH 按鈕)。半自動的能省下兩顆 transistor 跟兩顆電阻,但是由於編程的時候每次都要按 FLASH 和 RESET 有夠麻煩,所以我在設計的時候便選擇了自動燒錄器。以下是我參考的設計圖: 燒錄器設計圖 但是這設計圖差了點東西,就是圖裡沒有標注到 GPIO15 應該要 PULL LOW。在設計電路板的時候記得把 GPIO15 經電阻(如 10k)接地,這樣 SPI CS 才能正常使用。 為甚麼我會知道? 這真是個他媽的好問題(被坑) 這顆電阻雖然不加也可以,但是會無法使用 SPI 另外這兩顆 BC817 的 routing 也弄得我懷疑人生,不過後來還是在板上 route 好了。 我都不知道自己當晚是怎樣發神經想到可以這樣 route 的,嘛總之能動就好了。 其次:SD 卡 ESP8266 有內置的 SPI 針腳可以用來讀取 SD 卡。很多人以為 SD 卡模組上面有特別 IC 去把 SD 卡轉換成 ESP8266 可以讀取的信號,然而實際上的讀取方法聽上去有點奇妙,就是直接把 SD 卡當成 SPI Slave Device 來讀取。 那你會好奇,如果 SD 卡可以直接接 ESP8266,那外面在賣的 SD 卡模組上面那顆 IC 是幹甚麼用的?這是個好問題,那是防呆用的(不對) 你看,不是所有 MCU 都是在用 3.3V Logic Level 的說。例如說 Arduino UNO 在用的 Atmega328 就是支援 3.3v - 5v 輸入。SD 卡只能用 3.3V 讀取,過高的通訊電壓會把它弄壞,因此很多模組為了相容更多的開發板,只好加上一顆用來轉換信號線電壓的 IC,通稱 LLC (Logic Level Converter ,大陸好像叫 「電平轉換器」)。但是由於我在用的 ESP12E 只支援 3.3V,所以剛好與 SD 卡需要的電壓一樣,所以就不用轉直接接 MCU 就好啦。 不說不知道,如果你走去翻 Wemos D1 SD shield 的設計電路圖,它基本上就只有一個 SD 卡插槽,跟一顆差不多看不見大小的電容來做 ripple filter。真的有夠簡單欸 把兩個東西整合理起 當兩個電路都有了,剩下的部分就是把電路給整合到同一片板子上。我本來是打算用名片大小的設計,這樣做不但能有一種「這是送你的見面禮」感覺,而且也有更多的空間來寫使用教學,有點像國外嵌入式工程師大神做的能跑 Linux 的名片一樣 國外工程師做的,能跑 Linux…
ArozOS 的多帳號切換系統原理
講到多帳戶切換系統,通常你只會在一些類似 AWS 或者 Google 那樣大規模的系統裡面才會看到,然而這並不是沒有原因的。因為有時候部分功能為了權限上的分別,不少人比起想要設定一個擁有多權限群組的用戶,反而會比較喜歡以帳戶的方式來使用不同權限群組的作業環境。 早在好幾十個版本之前,ArozOS 就可以建立不同的權限群組而且讓一個用戶加入不同的群組 單用戶多權限群組設計 原先的 ArozOS 採用多用戶多權限群組的設計,簡單來說就是每個用戶都可以加入一個或以上的權限群組,而這個用戶能做的事情和存取的儲存裝置就是 UNION of 所有的權限群組。假設群組 A 只能存取 A 的儲存池,群組 B 只能存取 B 的儲存池,那一個用戶加入了 A 和 B 的群組之後便能存取 A 和 B 兩個儲存池的資料,並在此中間自由移動和開啟檔案。 然而,不知道是不是這設計對於現代人來說太複雜了,很多人就是不會用,然後問我到底要怎樣才可以建立更多自用的使用者帳戶。建立之後他們又會來問到底要怎樣才可以把檔案在用戶之間移動,我就一整個(嗯??? 多用戶單權限群組設計 所以後來我在跟用戶訪談的時候,發現其實他們比較多在用多用戶單群組的用法。簡單來說,就是一個用戶只有一個權限群組,當他們想要存取另一個權限群組的資料的時候,他們便會登出原先帳戶並登入另一個帳戶。這用法通常是用來處理一些對外的服務(例如 www 的帳號來處理跟 web service 相關的檔案),但是用在 cloud desktop 上的這種要求我猜我應該是第一個 implement 的說? 所以為了體驗這種奇怪的使用方法,我特別在 test bench 上架了一個網站,讓 www 帳戶來保存檔案。 在 www 上架的一個 html file 然後就開始設計帳戶切換的邏輯。首先,一般的帳戶切換做法是使用 client side cookie / session 對每個帳戶進行登入,然後讓用戶可以自由切換在該 browser 上任何未過期的 login session。然而,在 ArozOS 上這有點不太可行 ArozOS 的 authentication 是基於 cookie 而非 localStorage。如果設計改了的話對一些依賴 legacy login API 的系統會帶來嚴重問題ArozOS 是網頁桌面系統,相比起其他網頁的 stateless 設計,ArozOS 的桌面是 stateful 的,而且整個狀態是儲存在伺服器端部分用戶在 ArozOS 上使用 oAuth / LDAP 作為登入認證伺服器,加上之後有打算加入 Cluster Authentication System 等伺服器端較複雜的結構,在客戶端上儲存登入狀態可能比較難做到跨伺服器間的 user state transfer 所以結合上述原因,我們最後採用了一個叫 Switchable Accounts Pool 的設計。 Switchable Accounts Pool (SAP) 是一個我們設計出來的實驗性東西。它的功能大概就是以一個 pool id 來對應一堆可以切換的帳戶,而這些帳戶又會有 main / secondary 的關系,讓帳戶的登出的時候在伺服器端對該瀏覽器的登入狀態進行切換。 一開始,當主帳戶登入的時候,一個在伺服器端的 SAP 便會被建立。Creator 的名字就會寫著是主帳戶的名字。之後,用戶可以透過登入 sub-account 以取得在這個 session 結束之前,可以不斷切換到 sub-account 的權利。 當 Sub account 登出的時候,由於 main account 的 session 仍存在,因此伺服器端會直接改寫 User 的 login cookie 到原先的 creator account。 而當 Main account (即 SAP 的 Creator)登出的時候,伺服器端便會直接 discard 整個 SAP 以保護其他 sub-account 的安全(非法透過登入 sub-account 以取得 main account 的存取權)。 在邏輯搞清楚之後,剩下的便是把功能寫出來了。這裡只是一點簡單的 Go programming,技術上沒甚麼特別的所以我就不再詳談。 網頁桌面上的可切換帳戶 新增帳戶的時候需要使用密碼登入,如果是近來切換過的而 session 沒過期可以透過伺服器端免密碼切換 在一些特殊情況下,例如說 main account 的 login session expire 但是 SAP 的 session 還沒 expire ,使用者便會在登入界面看到這樣的一個 popup,讓他可以快速回復之前登入過的…
Zoraxy – 新手向 Reverse Proxy Server( 反向代理服務器)
我猜很多 web devs(網頁開發者)都知道什麼是反向代理伺服器 (Reverse Proxy Server)。當您在 homelab 或 cluster 上部署多個 service 並希望使用單一gateway server 和不同 subdomain 將它們 expose 在網際網路上時,反向代理伺服器尤其有用。在這篇部落格文章中,我就來分享一下我為什麼要用 Go 開發自己的反向代理伺服器來取代Apache / Nginx 和把它部署到我的分散式 homelab 中的經驗。 甚麼是 Reverse Proxy? 想像一下,你正在音樂節上隨著你最喜愛的表演,突然你想要一杯 冰涼的飲料。由於你不想錯過任何的表演環節,所以你派你的好朋友(即反向代理伺服器),去替你把飲料拿來(網頁內容)。你的朋友穿過人群,排隊等候,完全不會打擾你觀賞表演,最後在不知甚麼時候帶回了那杯冰涼的飲料。在這種情況下,反向代理伺服器扮演著你和音樂節混亂背後的幕後伺服器之間的中間人角色,隔離你(用戶)和後面混亂的內部網絡 routing,直接由中間人向你提供所需的內容。 不僅僅是為你轉發和中繼網頁內容 ,現代的反向代理可做到比中繼代理之外更多的事情。例如說負載平衡、故障切換(failover)等。像Nginx Proxy Manager(NPM,不是那個黑洞 npm)這樣的管理工具甚至具有內置的自動 SSL證書更新等功能。這就是為什麼反向代理通常被認為是 homelab(或任何類型的網站系統)的“核心”的原因。 那為甚麼我要重新寫一個屬於自己的 Reverse Proxy 伺服器? 如果你是一名資深的 devops 工程師,那你一定有親身體驗過寫 Apache 或 Nginx 配置文件的痛苦,那必定是一個難以忘懷的經歷。當你試圖從 Stack Overflow上 Copy & Paste 一些看不懂的東西到你的 config 檔,並試著根據自己的了解進行修改,卻發現怎樣 route 都是怪怪的。再加上很多開源專案都很依賴於 Rewrite Rules 和 Headers 中某些特殊設置的 Setting,要讓所有 service 都能正常運行真是一件讓人痛苦的事情。更多別提到你想加入一個臨時的 routing rules 做 testing 都要進入 ssh 到後台設置的麻煩( 在開源世界中,有一些替代方案或解決方案可解決這些問題。像 NPM 是 r/selfhost 上 Reddit 用戶最推薦的方案之一。然而,它已經快兩年沒更新了,而且聽說最新版本會弄壞很多東西。這就是為什麼我決定自己開發一個 Reverse Proxy 伺服器以解決自己未來可預見的「所有」問題。 這就是 Zoraxy 誕生的原因 Zoraxy 是一個以 Go 開發的 Reverse Proxy 伺服器。除了基本的功能外,還附了很多不同的工具和機能讓你輕易管理你的伺服器集群(當然也能用於 docker 了)。以下是一些簡單易懂的系統截圖: 登入後的主頁 一些 overview status Subdomain 設定 建立新的 Proxy Rules Proxy root (預設路由路徑) Certificates 重導向設置 存取管理 Uptime Monitor MDNS 與 IP scanner Web SSH 功能 用戶統計 登入界面 TCP Proxy (主要用來當遊戲伺服器路由,如 Minecraft Server) ZeroTier controller 有興趣了解更多或下載試用可以到 https://zoraxy.arozos.com/ 看看喔
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 輸入到模擬器)