Development Logs
Prototype built updates and some Q&A of a certain prototype can be found here.
Type C source & sink 的 CC pin 電路設計
因為最近我的專案都全面轉用 type C 來取代傳統的 micro USB 跟 type A USB port 了,避免開始工作一段時間之後忘掉了怎樣走線,所以就來寫一篇部落格來記錄一下。 Type C Sink (接收端,例如說要充電的裝置) 這個官方文件裡面是說需要把 CC 接 5.1K 到 GND。可是由於一開始規格內容沒很明顯,導致不少人誤解了這句話的意思,例如說 Raspberry Pi 4 一開始版本的 type C sink 設計就是有問題的: Raspberry Pi 4 錯誤的 type C sink 下拉電阻設計 一般來說如果你的電源供應器只輸出 5V 3A 的話倒是沒甚麼問題,但是一用到支持 E-mark 的 type C 線加上 PD 供電器就會出問題了。所以正確的接法應該像下面的, CC1 跟 CC2 獨立拉出來經 5.1K 電阻再接到 GND 上面去 我設計的 type C sink,注意 CC1 跟 CC2 是分開接到 5.1k 的 這樣 PD 電供就會知道這是一個 5V 的 sink 而輸出 5V 3A 的電壓 / 流了。 Type C Source (放電端,例如說充電器或是筆電) 接收端應該是比較多人知道,但是 Source 端就較少人討論了。技術宅老人可能知道,在很早的電子產品中, USB 接口預設最高只能提供 (5V)500mA 的電流。所以如果隨便把現代的電子產品插到 10 - 15年前的電腦上充電,電腦有時候會直接把那個 USB 口砍掉( 但是因為太多人拿 USB 來當一個充電接口,所以後來 USB-IF 加入了額外的規格來給需要 USB 充電的裝置使用,現在大家看到的 5V 1A、2A 到 type C 的 3A,都是後來 USB Battery Charging Specification (BCS) 跟 USB Power-Delivery (PD) 提供的。 因此在此背景下, type C device (特別是能用到 10W 以上的電子產品)在插上去的時候,是需要知道 Source 能提供多少的電流,是甚麼規格下的 USB 端口才敢開始充電。 source 的 pull-up 電阻規格 但是就一般 DIY 電路板來說,如果是做信號類的東西,我們就只要在 Source 端 CC1 跟 CC2 分別接個 56K 上拉(即 CC1 / 2 經 56k 到 VBUS (5V))就可以了。如果你在做的 source 是一個 5V 的充電器,能提供到 1.5A / 3A 的話,也可以按上表中改用 22k 或是 10k 的上拉電阻。例如說 Github 上這個開源的 type C USB hub 就是如此設計。
淺談 CSRF 與 CSRF Middleware
最近在我的 Zoraxy 開源專案那邊出現了這樣的一個 bug issue 他還很好的附了一個網頁測試介面的截圖 甚麼是 CSRF 攻擊? CSRF(Cross-Site Request Forgery,跨站請求偽造)是一種網絡攻擊技術,攻擊者通過在受害者不知情的情況下,冒充受害者的身份在受害者已經認證的網站上執行未經授權的操作。 CSRF 攻擊的工作原理 受害者登錄到可信網站:受害者首先登錄到一個需要認證的網站,在這例子是 Zoraxy 的後台管理頁面攻擊者製造惡意請求:攻擊者創建一個包含惡意請求的網頁或電子郵件,例如說這裡的一個 free burger 網頁 html + web form (action 或 form submit URL 指向 Zoraxy 的後台管理頁面)受害者訪問惡意鏈接:受害者在登錄狀態下 request 了攻擊者控制的網頁並提交了 web-form。執行未經授權的操作:由於受害者已經登錄(Auth Cookie 會跟著 form 一起送出去),Zoraxy webmin 介面會以為這些 request 是 valid 的,並執行相應的操作,例如上面例子的 toggle proxy 開關狀態 。 防禦 CSRF 攻擊的方法 CSRF Token:在每個受保護的操作請求中加入隨機生成的、唯一的 CSRF Token,並驗證這些 Token 以確保請求是合法的。檢查 Referer 和 Origin 頭:檢查 HTTP 頭中的 Referer 和 Origin 字段,確保請求是從合法的來源發出的。但是我在寫的是 Reverse proxy,本來 Referer 跟 origin 就是不可信的,所以不能使用此方法。雙重提交 Cookie:將 CSRF Token 存儲在 Cookie 中,並在請求中一起提交和驗證。使用 SameSite Cookie 屬性:設置 Cookie 的 SameSite 屬性為 Strict 或 Lax,限制跨站請求攜帶 Cookie。 說真的這也不是我第一次處理 csrf 問題。先前同一位使用者也對 ArozOS 提出過類似的 issue report。然而 ArozOS 因為是使用 agile 開發的,API 散落得到處都是,根本沒辦法用標準的方式來做 csrf middleware 來保護 API 接口,所以當時只用了一個非常不標準的方式來做(就是每一個 post request 之前都加一個要求 csrf token 的 ajax request,變成每個 request 都會變成要 request 2 次) csrf middleware csrf middleware 是一個 http Handler 並讓它來對 request 進行預處理並對不合規格的 POST (PUT / DELETE) 等 request 進行攔阻。所以這裡有兩個需要做的事情 在 HTML 頁面生成的時候,在頁面上加入一個 csrf token在有資料需要以 POST 等 request 回傳到伺服器時,在 payload 中以 header field 的方式附上頁面的 csrf token 在 ArozOS 的做法上,它是先對伺服器進行一個 csrf token generation request,然後再把 request 附到下一個 ajax POST request 裡面。這做法雖然不是不行,但是對於前端來說要改實在太複雜,而且一個 csrf token 又沒有那麼快 expire,不斷生的話只會浪費後端資源。 Production grade 的 csrf middleware 使用方法 由於 Zoraxy 的設計從一開始就按著標準的…
10 分鐘設定好 open web-ui 跟 ollama
open web-ui 是一個很方便的界面讓你可以像用 chat-GPT 那樣去跟 ollama 運行的模型對話。由於我最近收到一個 Zoraxy 的 bug report 指 open web-ui 經過 Zoraxy 進行 reverse proxy 之後出現問題,所以我就只好來裝裝看看並且嘗試 reproduce 出來了。 安裝 ollama 我這裡用的是 Debian,首先第一件事要做的當然就是安裝 ollama。教學在他們的網上有我這裡就直接寫 code 出來了。 https://ollama.com/download/linux curl -fsSL https://ollama.com/install.sh | sh 在執行這個 bash script 之後它會自動建立一個 systemd 的服務。預設 ollama 的 web server 只能透過 localhost loopback interface 存取,如果要透過其他網絡才能存取到 ollama 的 API 的話,我們就要讓它同時 listen to 其他的 network interface。最簡單直接的方式是把預設的 systemd service 檔案改成這樣: sudo systemctl stop ollama.service sudo systemctl edit ollama.service 然後在 service 檔案裡加入下面那行(見備注) ### Editing /etc/systemd/system/ollama.service.d/override.conf ### Anything between here and the comment below will become the new contents of the file # 加入下面這兩行 [Service] Environment="OLLAMA_HOST=0.0.0.0:11434" #下面的不要碰 ### Lines below this comment will be discarded ### /etc/systemd/system/ollama.service # [Unit] # Description=Ollama Service # After=network-online.target # # [Service] # ExecStart=/usr/local/bin/ollama serve # User=ollama # Group=ollama # Restart=always # RestartSec=3 # Environment="PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games" # # [Install] # WantedBy=default.target 儲存並退出之後重啟 ollama systemd 服務 sudo systemctl start ollama.service 抓模型 因為我比較喜歡用 CLI,所以我就直接透過 ssh 來順便把模型也載下來。這裡我在試玩的是 qwen:https://ollama.com/library/qwen 一般模型也會有不同大小,而我選這個是因為我要省空間(對,SSD 快要炸了),所以我就選了比較小的 1.8b 版本。你可以用這個指令來讓 ollama 準備這個模型: ollama run qwen:1.8b 如果要其他大小的模型的話,只要把後面的 1.8b 換成 4b / 7b 之類的就好了。另外比較有名的包含 llama3 之類也是可以透過這樣的方式下載。 值得一提 如果你的 root disk (Linux 的 / 或是 Windows 的 C: 硬碟)不夠空間跑你想測試的模型,你可以在啟動 ollama…
Zoraxy v3 – 適合新手的反向代理伺服器
最近我一直在進行相當多的 Zoraxy 更新。對於從未聽過 Zoraxy 的人來說,它是我的開源反向代理伺服器 (Reverse Proxy Server)。可以部署在你的 homelab 或server / NAS 裡面。 如果你對 Zoraxy 如何運作沒有興趣,單純是來找一個可以在 Windows 和 Linux 上運行的 Reverse Proxy Server,請按這裡。 v3 的新功能? 嗯,如果你之前使用過 Zoraxy v2,每次打開 Web 管理界面,你都會感到一陣沮喪的感覺。這是因為在開發 v2 的過程中,我沒有多餘的時間仔細考慮配色方案或設計一個具吸引力的界面配色(然而作為開源項目來說,這界面已經算是到達夠好 + 能用的設計)。 v2 homepage v2 的代理清單 現在 v3 長這個樣子 除了界面更新之外,Zoraxy 還添加了大量新功能,以 optimize proxy core 的功能(或者我可以說,因為有太多 user 是從 Nginx Proxy Manager(NPM)轉過來用 Zoraxy,所以有一些部分如果盡量接近 NPM 的設計會省下我很多處理 issue 的麻煩)。一般來說,這不是 NPM 的替代品,而更像是一個讓你更容易在測試和debug 時切換 endpoint 的 Reverse Proxy。但無論如何,我不介意人們提出感覺像 NPM 的 enhancement issues。 Default Site 在 Zoraxy v3 中,我們新增了對 Default Site 和多個 host name 的支援。 Zoraxy 的前身(名為“Web Proxy”,是 ArozOS 系統的一個子服務)設計僅用於處理單一域名的反向代理,v2 版本添加了對子域和其他主機名的支援,但由於是沒經過設計加進去的,所以對 user 來說有夠混亂( 使用者對 “Proxy ”、“Subdomain” 和 “Proxy Root” 的設定感到困惑然後又跑來開 issue。這就是為什麼在 v3 的設計中,我設計一個新的界面和設置邏輯。有了Default Site 的選項(對,就是 NPM 那個),那習慣用 NPM 的人可以輕鬆地切換到 Zoraxy 了。(順帶省下了我很多解釋東西怎樣用的時間) Default Site 提供 4 個選項供選擇。對於新手來說,你可能想要使用內部靜態網頁伺服器,在使用 "Static Web Server" 功能時將一個 "index.html" 文件作為你的網站首頁。這更像是傳統的 Apache 的用法,如果在 apache.conf 中沒有對應的 Virtual Host,所有的路由都會進入內置的靜態網頁伺服器,並從你的 /var/www/html 資料夾抓檔案來回應 request。 Redirection 和 404 Not Found 用起來也相對直接。對於 Redirection (重定向),你可以輸入要重定向的目標域名/IP 地址。在要將舊的(子)域名指向新域名,或者直接阻止那些未知/過時子域名的請求時滿有用的。 Wildcard 域名證書與 SNI 在 v3 中,我們 implement 了 TLS/SSL 證書查找邏輯中的 SNI。Zoraxy SNI 與其他 implementation 的區別在於,它不需要用戶輸入來將證書與特定主機名“鏈接”起來,而是會自動掃描並 serve 出對應的 TLS certificate。 在 v2 中,用戶需要手動為每個證書設置與匹配的域名。例如,如果你有一個證書可以涵蓋 a.example.com 和 b.example.com,你需要手動將其匹配關鍵字設置為 "example.com",才能使這個域名的 TLS 加密正常工作(不然會出現 self sign certificate error)。現在有了 Zoraxy v3 的自動證書查找邏輯,你不需要設定任何東西。只需上傳你的證書(或使用內置的 ACME 工具從你選擇的 CA 生成一個),Zoraxy 將自動解析並選擇正確的 certificate。唯一的限制是對於包含多個主機名的證書(例如 domain.com 和 anotherdomain.com),速度會稍微慢一些(可能需要 O(n)…
Concurrent & Racing Conditions (並發與競態條件)
最近因為我在開發 Zoraxy 時需要設計一個可以做到 high speed concurrent READ 跟間中 write 的 map,跟另一位高雄的工程師大佬討論了一個晚上,後來我發現原來滿多人對 concurrent / racing conditions 的處理有一定程度的誤解,所以我就來簡單的解釋一下最常見的誤解 - Check for locking。 問題 假設你有兩個 process,一邊要讀取一個無法同時讀寫的 map 資料結構(例如 Go 的 map[string]struct{}),另一個要寫入新的 key 到同一個 map。由於 map 並沒辦法處理 concurrent R/W,所以你要怎樣做呢? 解決方法 1:改用專用的 concurrent map (如 Go 的 sync.Map) 這個解決方法簡單直接,我就不再詳細解釋了。然而由於我在開發 Zoraxy 的 high concurrent access 特質,使用 sync.Map 的話會做成很高的 over-head,因此我並不是很想用它(但是也不影響 sync.Map 作為沒法解決時用的最後方案的決定) 解決方法 2:mutex lock 這算是比較正規的方案之一。在讀取和寫入之前先對 map (或是 slice) 進行鎖定,然後在寫入或讀取之後解鎖。這樣就能確保同時間只有一個 process 對這個 map 有 R/W access。但是這同時也會產生另一個問題,就是在 read lock 了之後,假設有另一個 process 也想同時進行讀取的話就必須要等前面的讀完,因此這個方案對於高並發的 request handling 來說並不是太有效率。 那聽到這裡的時候很多人會直覺的覺得:那只有 write 的時候 lock 就好啦,read 的時候檢查 map 是不是被 lock,沒 lock 的話就讀取。由於檢查的時候不會 lock,因此其他需要 read 的 process 也不會被擋不是嗎? 聽上去好像沒錯喔?讓我簡單寫一個 pseudocode 例子: function write(){ mutex.lock() map.write("foo", "bar") mutex.unlock() } function read(){ if (!mutex.isLocked()){ //Map is not locked var value = map.read("foo") print(value) }else{ //Map is locked, retry after 100ms delay(100) read() } } mutex 的部分可以是 programming language 自帶的 mutex 功能或是簡單的 boolean,效果都是一樣的。但是如果你有注意到,你不會找到 mutex.isLocked() 這個功能。 如果你需要用到這個,很大機會你寫錯了 這是為甚麼呢?那是因為 OS 層基本運作原理所引起的。這裡對於本科沒修 Computer Architecture (計算機架構)的工程師可能比較難理解。簡單來說就是,CPU 上就只有 n 個核心,但是你的作業系統上面有很多東西在執行,所以 OS 會對上面執行的工作(process)進行快速切換。每次切換的時候因為速度很快,所以會讓你有一種它們在並行處理的感覺。而實質上,每個 process switching 都會有一個 overhead,而這個 overhead 就是為甚麼 mutex lock 沒辦法被用於檢查的原因。 其中一種常用的 scheduling 演算法:Round Robin Process Switching 關於 CPU scheduling 跟 scheduling 演算法的詳情可以看這邊 所以為甚麼 Mutex 不能檢查是不是被其他 process 鎖上? 當你去檢查一個 mutex 是否被鎖的時候,檢查當下可能沒被鎖,但是檢查完到執行下一個邏輯的時候可能已經被另一個 process 鎖上了…
從零開始自幹房間自動化燈光系統(Part 1)
說到我房間裡的 IoT 控制系統,從 2021 年起我就一直在用一套自己開發的 IoT 協議名為 Home Dynamic。這套系統的原理和詳情可在我另一篇文章( 從零開始的 IoT 系統設計 )裡找到,但是簡單來說它就是一個很簡單的 HTTP RESTful request 模型下的迷你 IoT 系統,可以用於開關電燈和透過 Tasmota firmware 來控制幾個 Sonoff 的 WiFi Smart Switch 而已。 到最近,因為我香港的房間要整修,所以我就把房間裡有點 hacky 的系統升級到新的自動化系統。Home Dynamic v2 (簡稱 HDSv2)雖然在設計的時候已經有考慮到很多不同的使用場景和可能出現的問題(如 off grid control,伺服器 / relay 的 SPOF 等等),但是其控制 latency 總是讓我覺得有點煩惱。即使後來 ArozOS 改用 Golang 重寫,從按按鈕到電燈真的亮起的時間大概也只是在 2 - 3 秒內,這個速度跟我去按一個物理開關還是有很明顯的差別。所以在新裝潢的房間裡,我採用了一個更新版本的 HDS 協議來開發我的新自動化系統,現在我把它暫稱為 HDSv3。 控制器硬體部分 那說到 IoT 跟自動化,在提軟體之前一定要先講講硬體。畢竟只要硬體夠強,軟體再爛也是能跑得很順暢(望向 python) 。這次為了未來的擴展性和標準化,這次我選用了半工業級的硬體。下圖中是我用的繼電器模組,是一片市售的 4 路 WiFi 繼電器模組。它是使用 ESP12E 作為主控制器,跟先前的 HDSv2 一樣都是基於相同的 MCU。因此大部分 HDSv2 的源碼能夠直接移植到 v3 然後下載到這片板子上。雖然這片東西可以使用 110 - 220V 輸入,但是因為我原先整套系統都是用 24V 的,因此這部分的機能就白白被我浪費掉了( 那當然,這片東西不能就這樣放在我的桌面上。因此我買了一個 DIN Rail 用的外殼,然後把整個組好的安裝到 DIN Rail 上。 現時的照明控制系統 那你可能會好奇,既然是控制燈光,那一個簡單的繼電器模組就可以做到了。旁邊那兩個盒子又是甚麼? 如果你仔細看一下那個繼電器模組的照片,你就會發現那個模組真的單純在做切換而已,它本身並沒有供電能力。所以為了讓接上去的 LED 燈條有電力供應,就必須透過另一個裝置為 Relay 的 NO (Normally Open)端供電。這裡中間的模組就是作為一個 power distribution hub 的用法來提供 4 個相同於 Vin 的輸出和 3 個可調節的輸出。 大概原理 而最左邊的是 LED strip 的限流模組,大概就是因為 24V 的燈條用 24V 供電的話會太光,所以那個小黑色模組裡面是一個簡單的 XL6009 自動升降壓模組來把電壓調整到大約 19.2V (我喜歡的亮度) 原本是長這樣的,後來想了想還是把它放到 DIN Rail 上比較好 軟體與控制部分 講到軟體部分,就不得不提一下 IoT 技術了。說真的,雖然我知道很多不同的 IoT 通訊協議,從 MQTT(DIY 很多人用,基於 TCP/IP)、 Zigbee (IKEA 那套)到工業用的 RS485 / RS232 之類的,我還是比較喜歡用 2.4Ghz WiFi。雖然距離短、用電量高,但是本來我的裝置就是用來控制電源的(aka 長期會有電源供應),加上香港地方實在太少,我想盡量省下一個放 hub 的空間 + 本身房間已經有 WiFi 覆蓋,所以自然地 WiFi 是最好的選擇,所以我還是選擇了基於 TCP/IP 的協議。 考慮到設備的相容性、不用額外安裝程式便能控制等優點,在眾多基於 TCP/IP 的協議下我選擇了 RESTFUL。一來是所有手機都有網頁瀏覽器,即使伺服器炸掉只要有一台手機能連接到同一網絡便可以透過 p2p 的方式控制 IoT 裝置。另一個好處是 RESTFUL API 實在太通用了,從 ESPHome 到 Home Assitant,最好支援的裝置類型依然是基於 RESTFUL API 的裝置,再加上怎樣看 HTTP request 這東西在未來 10 年應該都會還存在(畢竟是 Web 技術的基礎),選它一定沒錯( 而為了解決…
在 Zoraxy 加入 TLS SNI 功能
最近我在開發的 Zoraxy v3 在我開發 Zoraxy 之前我也不知道 https 證書這東西對於 reverse proxy 伺服器來說到底有多複雜。一開始的時候因為我都是用一個域名(domain name),所以 reverse proxy 裡面也是只需要處理一個主機名稱(host name)。而初代的 Zoraxy 則是直接用 TLS hello info 裡面的 server name 作為 certificate 的 key 來找到合適的 certificate 並回傳給客戶端,所以時間複雜度(time complexity)而言是 O(1) 的速度。換成程式碼大概長這樣: http.ListenAndServeTLS(":443", "server.crt", "server.key", nil) 到後來發現 virtual directory 帶來的麻煩後,Zoraxy v2 加入了 sub-domain 的支援。為了解決找 certificate 的問題, v2 的做法是讓使用者把每個 sub-domain 都 map 到一張 certificate 上面,所以結果就是同一個域名下會有很多張證書(例如說 a.example.com 會有 a.example.com 的證書、b.example.com 會有 b.example.com 的證書)。這樣設計的好處是一來找 certificate 的演算法比較簡單,二來我們可以根據 hello info 的 server name 進行也是 O(1) 時間複雜度的 certificate lookup,不用任何存取 file system 的 loop 便可以直接找到證書。 if fileExists(helloInfo.ServerName+".pem") && fileExists( helloInfo.ServerName+".key") { //Direct hit pubKey = helloInfo.ServerName+".pem" priKey = helloInfo.ServerName+".key" } 然後在 Zoraxy v2 用了這一年多之後就又出現問題了。coauthor 的其中一張證書裡面包含了幾個不同的 domain 跟 subdomain,也有使用者的證書是含 wildcard 的,也有是舊版用 Common Name 來定義(而不是 DNS entry)來標記 host name 的,結果就是一大堆 issue 就出現在 repo 上面。 SNI 的基本概念 SNI 的原理大概就是由伺服器端跟據 TLS Hello Info 的 Server Name 來自動回傳合適的 certificate 給 Client (這裡因為 Zoraxy 是一個 http proxy,那我就以瀏覽器為 client 的例子)。對於很直接的域名例如說 v1 跟 v2 裡面出現的,基本上就是只要把 certificate map 到一個 string 轉 certificate 的資料結構裡面就可以了。但是對於 v3 之後的複雜案例,則是需要一些更複雜的邏輯來處理。 相信來得我部落格的人不是工程師應該都是技術大佬,所以我就直接把 code 拿出來講好了。這裡是 Zoraxy v3 TLS 解釋器裡面最重要的 function func(m * Manager) CertMatchExists(serverName string) bool { for _, certCacheEntry: = range m.LoadedCerts { if certCacheEntry.Cert.VerifyHostname(serverName) == nil || certCacheEntry.Cert.Issuer.CommonName ==…
ArozOS 的桌面大更新
之前有一段時間我都在想幫 ArozOS 的桌面做一個大更新,把最頂部的仿 Ubuntu 狀態欄拿掉,可是因為開刀和學業上各種事情一直沒空完成。最近新年前剛好指導教授不在一個禮拜,所以我就來更新了一下這個久久沒時間完成的小目標。 原先 web-desktop 的界面,上下都有一個黑色的功能欄 新的 web-desktop 界面,最頂部實色的被整合到下方的欄內 日曆和通知也被移到右下方 右下方角落的那個圈圈就是以前在右上方的背景執行工作列表 其中我最喜歡的功能大概就是這個系統一覽表了。從伺服器的在線狀態,名稱,SMART 狀態到各顆硬碟的使用量都能夠直接看清楚。 嘛當然除了這個以外還加入了很多微細的使用者體驗最佳化,例如說背景加深 + 模糊的狀態來突顯某個元件之類的 未打開日曆前的背景 打開日曆後加入的 backdrop-filter blur,突出了日曆和通知欄的前置感 另外也加入了能直接進入進階分享設定的功能按鈕,比起以往要進入到 File Manager 來更改進階設定要來得更方便。 這樣的界面大概已經算得上是追到近年的 web-desktop 界面水平了吧?雖然說在 github web-desktop 的分類排行中 ArozOS 是掉到了第四位,但是以完整性來說 ArozOS 還是跟 DSM 比得上的 web-desktop 類界面(
Golang – 加速抓資料夾的總大小的方法
最近因為一些意外所以要頻繁跑醫院回診,結果就是在等待跟來回的時間前後多了很多零碎的時間,所以我就不浪費這些時間來幫我用了快 6 - 7 年的 ArozOS 系統做了點更新了。但是這篇部落格並不是在講我更新了甚麼(雖然某程度上也是),而是講一下關於 Golang 處理 exec 輸出的一個小發現。 背景故事 - ArozOS 的 Disk Properties 載很慢 ArozOS 的 Disk Properties ArozOS 因為採用半虛擬磁碟架構的設計,所以每次要列出 disk space 的時候,除了一般像 Windows 那樣會列出用了多少跟全部空間是多少以外,如果磁碟空間是使用者分隔的,就要多計算使用者佔用的空間比(圖上黃色條) 這個功能原本是使用 Walk function 來實現的。因為 ArozOS 的 vfs architecture 關系,這裡我使用的是 ArozOS 專用的 filepath module (你可以把它想像成 Go 原本的 filepath.Walk var size int64 = 0 fshAbs.Walk(rpath, func(_ string, info os.FileInfo, err error) error { if err != nil { return err } if !info.IsDir() { size += info.Size() } return err }) filesize = size fshAbs 是 file system handler abstraction 的意思,大概就是「這個虛擬磁碟的檔案系統層」的 object。 另外 rpath 就是從 user space translate 過來到這個 abstraction layer 的實質路徑,如果是本機磁碟的話就會是好像 /media/storage1/users/{username}/myfile.txt 這樣的 path;如果是 network drive 的話會是跟 mount-point 的相對路徑,例如 WebDAV 或是 FTP 下就可能會出現 /myfile.txt,或是 SMB 下的 /Share/myfile.txt 之類。 這樣的 implementation 你一看就可以知道這個在 Network Drive 上是不可能實現的,因為每一個檔案 Go 都要抓它的 Stat,即是遠端有多少個檔案就會送多少個 file request 過去,所以自很早之前就 ArozOS 的 File Manager 就加入了 這個簡單粗暴的解決方法… if fsh.IsNetworkDrive() { filesize = -1 } 然而隨著我在用的 NAS 東西越來越多,這個 walk function 即使在 local disk 下也開始變得很慢。 那改用 kernel 內置的 API 來抓不就好了嗎? 確實如此。Linux kernel 裡其實有內置一個滿好用的指令叫 du,用起來也超簡單,只要: du -sb /media/storage1 481491222874 /media/storage1 那這個資料夾總大小(byte size)就出來了。如果你想要 block size 的話可以把 b 去掉。然後就是寫一個簡單的 Go function 去把資料抓出來。 /* Get Directory Size with native…
透過 JLC PCBA 特殊零件的方法 – Consign Parts
最近我在開發一個全自動 USB TYPE C 的回流焊加熱板,需要用到一顆特殊的 PD trigger IC - IP2721 (TSSOP-16),雖然它是存在於 JLC Library 裡面,可是因為全球性供貨問題而導致沒存貨。 Order Parts - 要求訂購零件 JLC 提供一個功能叫 Order Parts,但是它並不是訂購然後附在 PCB 盒子裡給你,而是只限於用在 PCBA 上的。這個就比較簡單,當你在 PCBA 下單的時候看到需要的零件沒貨,就可以先取消訂單,然後到 Parts Order 頁面下單你需要的零件 但是由於這顆 IC 實在太難找,所以在 Order Part 所有 Supplier 都沒有的情況下,我要求了一個新的 part request。 Part Request 的流程大概這樣: 填寫你要求的零件 Mft Part Number ( 原廠零件編號 ,例:IP2721)跟 package (封裝規格,例:TSSOP-16)它會預估一個金額給你(例:0.5590 / pcs),(這個金額是預估的,如果報價不準我猜他們應該會自行吸收或是要你補差價?)並以這個金額付款訂購它會進入一個叫 Quotation 的流程,一般來說這會卡個 2 - 3 天然後如果成功 quotation 的話應該很快就會出現在你的個人 part list 了。 然而由於這顆 IC 實在到處都沒貨,所以最後還是收到了 JLC 的退款。。。 那問題就來了: 如果連他們也沒辦法 source 到這顆 IC,到底還有甚麼辦法可以買到這顆東西呢? 不說不知道,還真的有。 JLC 還備有最後一個 fallback 用的功能,就是 Consign parts。簡單來說就是你可以透過第三方郵寄材料到他們的 SMD 倉庫,然後再由他們手動加入到你的 part list。 做法也是很簡單,首先到 Consigned Part List 裡找到你要的零件 Mft 號碼跟 package,然後點 Add to Consignment 然後只要根據他提供的地址把零件送過去就可以了。說起來很簡單,但是最困難的部分還沒出現:就是採購和運輸。 在選擇好之後會顯示個人化的收貨地址,由於含個人資料所以這裡我是抓 JLC 網站的範例圖 你看,PCBA 這東西當然是不可能靠人手來做而是使用 PnP 機器來做。因此例如散裝、袋裝之類的零件,他們是沒辦法用的。對於這個,他們的客服跟我說如果送過去的包裝不對也能貼,但是會每顆收取 0.14USD 的手工貼片服務費,以通俗的說話來講就是「你他媽的最好不要送錯喔」 他們接收而免手續費的零件包裝種類只有兩種:1. 編帶 (一條 (不能是散裝多條用膠帶黏起來)或 一整卷編帶 )2. 托盤 那了解這個之後就可以訂零件了。由於 JLC 只接收中國大陸內的物流,所以這個時候就需要聯系華強北的專家來處理了(還好平常進口電子零件的時候收集的店家名片沒扔掉)。簡單來說就是提供你要的零件 Mft 號碼、 package 、數量,跟指定一定要單一條編帶 + 防靜電袋 + 寫上 Mft No. 發貨即可。雖然說他們建議使用 SF 物流,但是基本上只要能送到即可。 大概 3 - 4 天之後就出現在 Consignment part list 裡面 最後只要在 PCBA 的時候選擇從 My Parts 裡面抓這顆零件就可以了~ 我的板子終於要生產了啦 備注 備用件 有時候部分零件 package size 是屬於容易貼錯的大小,在你第一次 PCBA preview 的時候它會出現建議數量 > 實際所需數量的情況(例如說這裡我只做 50 片,IRLR8726T 卻要求你給 52 片) 如果這個情況剛好出現在你的 Consignment parts 上面,記得多買幾顆送過去。一般來說中國買的集成電路(含郵票孔類的模組,除非你是從一些大廠那邊買)類產品會有 8 - 10% 的不良率,所以多準備 10% 應該是足夠的了。 DIP 與 SMT 價差 如果想省錢的話,把需要插件的零件都從 BOM 表中拿掉可以省不少喔!(不過更佳的做法當然是在設計電路板的時候盡可能換成…