發表文章

目前顯示的是 8月, 2025的文章

網際網路筆記:3GPP

什麼是 3GPP? 3GPP (3rd Generation Partnership Project)是一個 國際合作計畫 ,成立於 1998 年,由多個標準化組織共同推動。其目標是為全球行動通訊制定統一的技術規範,截至 2025.08 已經定義完 3G (UMTS) 一路演進到 4G (LTE)、5G (NR),並積極規劃 6G。  我自己的理解是:3GPP 是一個「是一個制定標準的組織」,他們制定了某個行動通訊技術的網路架構。 3GPP 架構 UE → RAN → Core Network UE (User Equipment,使用者設備) 使用者設備、終端機,負責收發無線訊號與協議交換 RAN (Radio Access Network,無線電接入網) 負責將使用者設備連接到核心網路,並管理無線電資源、封包傳輸、基本的網路品質控制 3G 分散式 NodeB ( 3G 裡的基地台,負責與手機進行無線通訊) 集中式 RNC (控制多個 NodeB,負責無線資源管理) 4G:eNodeB (既是無線電基地台,也自行處理無線資源管理,不再需要額外的 RNC) 5G:gNodeB (5G 的基地台) Core Network (核心網路) 負責連線控制、流量交換與服務管理 3G (UMTS):語音與數據分開處理 主要元件 如下: Circuit-Switched (CS) Core:用於傳統語音通話  Packet-Switched (PS) Core :用於上網與封包傳輸 4G ( LTE): 語音通話不再走傳統 CS,而是透過 VoLTE (Voice over LTE) 傳輸 主要元件 如下: MME (Mobility Management Entity):控制訊號、管理 UE 的連線狀態 SGW (Serving Gateway):處理使用者封包轉送 PGW (PDN Gateway):負責 UE 與外部網際網路的連接 5G (NR):各個核心功能模組以服務的 方式  (ex:用 API 呼叫)  彼此交互 主要元件 如下: AMF (Access and Mobility Management Function):取代 4G 的 MME SMF (Session Management Function):負責數...

網際網路筆記:TCP

TCP 內容太多了,單獨開一篇整理。 整個 TCP 的傳輸是由 RFC 793 定義,一般念書考試不會去讀、開發單個項目也不一定需要,根據我之前實作其他協議的經驗,大概做研究或從 0 開始做一個簡單的 TCP 連線才會需要好好讀完。    TCP 的託運單(header)  因為在下面條列讀起來太累了,我試著用 title 對每個欄位的意思做了註解,把滑鼠移上去就可以知道該欄位的用途。  此外,下面的 header 範例是一種 pseudo-header,屬於一種概念,開發不一定也長這樣。  0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 Source address (來源 address) Destination address (目的地 address) SN (序列號) ACK (確認號) Data offset 保留 N S C W R E C E U R G A C K P S H R S T S Y N F I N WIN Checksum Urgent pointer 接下來還有 Options ,改天再更新吧。  TCP header 一般會在 20~60 個 bytes (上面的表格中,一行為 32bits = 4 bytes),補上 option 後會洛在這個長度裡。   TCP 的 3 次握手 (建立連線)  這邊會用到上面 header 中 SYN、ACK (flag)、SN、ACK (確認號,下面用小...

演算法筆記:Qsort

quick sort 的演算法簡直是我最熟悉的陌生人,競賽、上課那幾個時候跟他都還挺好的,但好像只要一陣子不寫(其實現在除了考試或刻意練習外也不太容易用到了,內建的 sort 很好用),就忘得要從 google 搜尋開始,乾脆自己寫筆記吧,看能不能記住點。   什麼是 Quick sort?  一種分而治之(Divide and Conquer)排序的演算法,排序 n 個項目要 O(n log⁡ n) 的時間複雜度,在最壞狀況下則需要 O(n*n),常用程度和必考程度都很高的一種演算法。 核心架構與實作 選定一個基準值(pivot) 將所有比 pivot 小的值擺在 pivot 之前、比 pivot 大的擺在後面 到剛剛分類完的子集合中遞迴執行上面的步驟  如果上面看完還不能理解,可以在 youtube 搜尋 quick sort, 觀察整個排序過程 (這邊找了一個我自己看得懂的)。   程式實作(C++) int partition(vector<int>& arr, int low, int high) { int pivot = arr[high]; // 取最後一個元素當 pivot int i = low - 1; // i 代表小於 pivot 的最後位置 for (int j = low; j < high; j++) { if (arr[j] < pivot) { i++; swap(arr[i], arr[j]); } } swap(arr[i + 1], arr[high]); // 把 pivot 放到正確位置 return i + 1; } void swap(int &a, int &b) { int temp = a; a = b; b = temp; } void quickSort(vector<int>& arr, int low, int high) { if (low < high) { int pi = partition(arr, low...

嵌入式系統筆記:ISR

ISR 是什麼? 全稱 Interrupt Service Routine,翻譯為中文則是「中斷服務常式」(?)。 是中斷發生時由 CPU 執行的一段特殊函式,用來處理外部或內部事件。   ISR 的流程 觸發中斷,中斷原因可能是:  外部中斷 (ex:按鍵)  內部中斷 (ex:定時器溢位、資料接收完成)  軟體中斷:OS 或應用程式主動觸發 CPU 暫停目前正在執行的程式、並儲存狀態 跳到對應的 ISR 執行 ISR 處理完畢後,CPU 回到原本的程式繼續執行   實作 ISR 的注意事項 核心概念:立即、簡短、避免等待性操作。  ISR 通常有較高的權重,會打斷比它權重低的程式 保持 ISR 的簡短 僅處理最必要的工作(ex: 紀錄 flag、讀寫 register) 硬體相關工作會放 ISR  不呼叫 system call、IO 等需要等待的指令  耗時動作會丟回背景或主迴圈裡 保護共用參數:通常會以   volatile 宣告 清除 interrupt 的 flag:沒清掉會陷入 ISR 迴圈 ISR 不該有 return 的值 下面是一個考試上常見的糾錯程式: __interrupt int timer_isr(void) { static int counter = 0; counter++; char *buf = (char*)malloc(100); // 錯誤:ISR 內呼叫 malloc if (buf != NULL) { sprintf(buf, "Counter = %d\n", counter); // 錯誤:ISR 內呼叫 printf/sprintf free(buf); } return counter; // 錯誤:ISR 不該有 return value }   總之,ISR 應該寫得很簡單,只能做必要的 flag 設定、計數或讀寫 register。

C 語言筆記:Bit 操作

在低階程式設計、嵌入式系統、驅動程式開發中,我們常需要直接操作變數的位元(bit)。 下面筆記幾種工具/用法。   Bitfield 在 struct 裡面用位元為單位定義欄位大小。  struct Status { unsigned int power : 1; // 1 bit unsigned int error : 1; // 1 bit unsigned int mode : 2; // 2 bits unsigned int count : 4; // 4 bits }; int main() { struct Status s = {1, 0, 3, 9}; printf("Size of struct: %zu bytes\n", sizeof(s)); return 0; } 在一些系統中會搭配 union 使用 (請參見 C 語言筆記:保留關鍵字  中的 union)。  另外要注意的是,bit 的順序可能會隨著系統、編譯器的不同而有所改變 (請參見 C 語言筆記:little endian 與 big endian )。跨平台開發時,必須考慮 Endianness,否則同一段程式在不同架構可能產生相反的結果。   Bitwise  針對 bit 進行的運算。 常用運算子: &:AND |:OR ^:XOR;不同為 1,相同為 0 ~:NOT;反轉所有 bit <<:向左移位並補 0(相當於乘 2) >>:向右移位並補 0(相當於除 2)  因為 signed int 在許多計算中會出現,所以在 Bitmask 設定第二個 bit: value |= BIT2; 清除第二個 bit: value &= ~BIT2; 切換第二個 bit: value ^= BIT2; 檢查第二個 bit 是否為 1: (value & BIT2) != 0;

C 語言筆記:little endian 與 big endian

電腦記憶體是以位元組(Byte)為單位儲存資料的,但多位元資料(例如 int、long)在記憶體中的儲存順序,會依不同系統而異。   儲存順序 big endian:高位元組存放在低位址  little endian:低位元組存放在低位址,從人類角度來看像反著寫數字 直接用例子會比較容易理解,假設我們有個 12345678 的數字,在兩種儲存順序中如下: Big   Endian: addr → [12] [34] [56] [78] Little Endian: addr → [78] [56] [34] [12]    比較:    Big Endian Little Endian 直覺性 高(符合人類閱讀順序) 低(反序) 處理數值運算 較複雜 較方便處理低位元組運算 常見架構 網路協定、部分 RISC   x86 、 ARM (預設 Little Endian ,但可切換) 使用情境 在網路傳輸的協定中,統一使用 big endian,避免接收端的 CPU 需要額外判斷收到的資料需不需要轉換、也能減少傳輸封包大小(不需要另外儲存一個值來協助判斷)。   而在 CPU 運算中,little endian 發揮較好。 在做運算與硬體設計上,要判斷進位與借位(ex: 21 - 13,我們需要先知道 1 < 3 才會觸發借位)的傳遞、硬體實作邏輯也是從低位開始算,若採用 big endian,必須先「預測」低位的進位情況,這樣會使電路變得非常複雜,計算速度也不好。  

C 語言筆記:指標

練習題 題目取自 軟韌體工程師的 0x10 個問題 與 C/C++ - 常見 C 語言觀念題目總整理 ,題目下一行反白是答案。 如果這邊能全對表示對指標有一定的掌握程度,不需要往下看了。  一個整數 (An integer) int a; 一個指向整數的指標 (A pointer to an integer) int *a; 一個指向指標的指標,它指向的指標是指向一個整型數 (A pointer to a pointer to an integer) int **a; 一個有10個整數型的陣列 (An array of 10 integers) int a[10]; 一個有10個指標的陣列,該指標是指向一個整數型的 (An array of 10 pointers to integers) int *a[10]; 一個指向有10個整數型陣列的指標 (A pointer to an array of 10 integers) int (*a )[10]; 一個指向函數的指標,該函數有一個整數型參數並返回一個整數 (A pointer to a function that takes an integer as an argument and returns an integer) int (*a)(int); 一個有10個指標的陣列,該指標指向一個函數,該函數有一個整數型參數並返回一個整數 (An array of ten pointers to functions that take an integer argument and return an integer) int (*a[10])(int); const int * a; 的意思 一個 pointer,指向 const int 變數。 int const * a; 的意思 一個 pointer,指向 const int 變數。 int * const a; 的意思 一個 const pointer,指向 int 變數。 int const * const a; 的意思 一個 const pointer,指向 const int 變數。 什麼是指標? 一個指向某個儲存位址的變數。 如果變數是房子,那指標就相當於地址。 int arr[5] = {10, 20, ...

C 語言筆記:保留關鍵字

什麼是保留關鍵字? C 語言的關鍵字是由編譯器保留、具有特殊用途的單字。簡單舉例:if。 它們是語言的語法組成部分,編譯器會將它解讀為語法指令,所以 不能作為變數、函數或其他識別符的名稱 。 目前依照 C 語言版本不同有不同數量的保留關鍵字, ANSI C 標準中 32 個保留關鍵字、到 C99 有 37 個、C11 有 44 個。 下面依照功能不同列舉,黑色是 ANSI C 標準, 藍色 為 C99 增加的, 紫色 則是 C11 增加的, 粗體 為有額外說明。部分面試常見、我自己有些心得的保留字會有額外的筆記。   流程控制關鍵字 if          else        switch     case        default for        while      do           break       continue goto     return 資料型態關鍵字 void      char            short             int         long float      double        signed          unsigned _Bool    _Complex   _Imaginary struct    union         enum unsigned:常見...

演算法筆記:Backtracking

什麼是 Backtracking? Backtracking 中文直翻叫「回溯」,在演算法中是一種搜尋方法。 其核心思想為:  嘗試一條路徑,若發現不符合條件,則回溯,然後嘗試其他可能性。 可以將其想像成一種 DFS 的延伸, 但相較於 DFS,Backtracking 會找出「所有」、「可能」的解,並透過提早刪除不可能的路徑來提高效率。(當然,DFS 也能寫複雜一點做到這些,但在描述 DFS 演算法時,我們並不預設它需要寫得如 Backtracking 複雜)。 什麼情況下我該想到 Backtracking? 找出所有可能、路徑、解法 每一步都需做出選擇(如選哪個數、放在哪個位置) 解的過程為試錯,需要回退到前一個狀態 如果有上面特徵、外加有明確的限制時,就要提早刪除不可能的路徑。 核心架構與實作 定義每一個步驟的選擇 列出當下所有可能選擇 終止條件 回溯 提早刪除不可能的路徑 不是必須,但需要提升效能時可以優先從這裡著手 這邊以「 Leetcode 46: Permutations 」以 C++ 實作為例,說明上面架構。 class Solution { public: vector<vector<int>> result; vector<int> gNums; int gNumsLen; vector<vector<int>> permute(vector<int>& nums) { if (nums.size() == 1) { result.push_back(nums); return result; } gNums = nums; gNumsLen = nums.size(); vector<bool> mark(nums.size(), false); vector<int> subSet; findPermute(mark, subSet); return result; } void...