1. 程式人生 > 實用技巧 >工程實踐中的軟體科學

工程實踐中的軟體科學

從軟體系統分析和設計到軟體系統概念原型

          ——基於工程實踐:智慧物聯結點的設計與實現

一、概述

  本文主要是針對智慧物聯結點的設計與實現這一工程實踐,對其進行軟體系統分析和設計到總結出軟體系統概念原型。闡述專案中所蘊含的軟體結構特點,比如基本結構和特殊機制、設計模式、軟體架構風格和策略等,並給出資料庫核心設計的分析以及原始碼的檔案目錄結構。ESP-WROVER-KIT是一款基於ESP32無線網路和藍芽/藍芽低能耗(BLE)片上系統(SoC)的全功能開發板。該開發板相容基於Espressif系統的雙核無線雙模藍芽模組,包括 ESP-WROOM-32 和 ESP32-WROVER。

二、軟體的基本結構和特殊機制

  基本結構包括五種:順序結構、分支結構、迴圈結構、函式呼叫框架以及繼承和物件組合。前三種最基本的結構是實現大專案必須的,在ESP32的開發板的各個硬體裝置實現中,均用到了函式呼叫:GPIO引腳函式中呼叫高低電平設定函式、看門狗呼叫一系列操作TWDT的函式等。繼承和物件組合是類與類之間的兩種關係,在軟體設計中,考慮到物件間的依賴程度和耦合程度,物件組合下的兩個類表現為鬆散耦合。繼承可以重用程式碼,但是會破壞了程式碼的封裝特性,增加了父類與子類之間的程式碼模組耦合。所以,避免使用繼承,在每個ESP32的硬體設計中,多半採用物件組合來實現目標,比如,在實現ESP32的VFS中,記錄了檔案路徑與檔案系統之間的對應關係的 vfs_entry_t 結構與檔案系統結構的對映關係就是物件組合模式。

  同繼承、物件組合同樣關鍵的概念還有一個多型,多型是一種比較特殊的機制。

 1 const esp_timer_create_args_t periodic_timer_args = {
 2             .callback = &periodic_timer_callback,
 3         // 設定回撥函式
 4             .name = "periodic"  // 定時器名字
 5 };
 6      // 定義一個單次執行的定時器結構體
 7 const esp_timer_create_args_t oneshot_timer_args = {
8 .callback = &oneshot_timer_callback, 9         // 設定回撥函式 10 /* 這裡指定的引數將被傳遞給定時器回撥函式 */ 11 .arg = (void*) periodic_timer, 12 .name = "one-shot" // 定時器名字 13 };

  另外,還有回撥函式,如上程式碼。回撥函式是一個面向過程的概念,通過函式指標呼叫的函式。把函式指標地址作為引數傳遞給另一個函式。還有的特殊機制包括:閉包、非同步呼叫以及匿名函式。這裡閉包找到的是同一地址下的父級函式中對應變數最終的值。此工程實踐中,在Timer定時器設計中,運用了大量的回撥函式,作用就是通過設定等待時間,在到達等待時間之後執行指定的硬體操作。

二、介面API

  這裡分析的API介面是基於ESP-WROVER-KIT開發板中各個硬體裝置的獨立API。

2.1 GPIO裝置

通用輸入/輸出口(引腳),通過這些引腳輸出高低電平或者讀入引腳的狀態。列出部分API函式名和功能:

1 esp_err_tgpio_config//GPIO通用配置
2 esp_err_t gpio_reset_pin//將GPIO重置為預設狀態
3 esp_err_t gpio_set_intr_type//設定GPIO中斷觸發型別
4 esp_err_t gpio_intr_enable//使能GPIO模組中斷訊號
5 esp_err_t gpio_set_direction//配置GPIO的方向
6 esp_err_t gpio_set_level//設定GPIO的輸出電平

2.2 UART裝置

通用非同步收發傳輸器。列出部分API函式名和功能:

1 esp_err_tuart_intr_config//配置UART中斷
2 esp_err_tuart_set_word_length//設定UART資料位
3 esp_err_tuart_set_parity//設定UART奇偶校驗模式
4 esp_err_tuart_set_stop_bits//設定UART停止位
5 esp_err_tuart_set_mode//UART設定通訊模式
6 esp_err_tuart_driver_install//安裝UART驅動程式
7 intuart_write_bytes//從給定的緩衝區和長度將資料傳送到UART埠
8 intuart_read_bytes//UART從UART緩衝區讀取位元組
9 int uart_tx_chars//從給定的緩衝區和長度將資料傳送到UART埠

2.3 LEDC裝置

全綵LED燈。給出其API介面的示意圖:

2.4 Timer

通過設定等待時間,在到達等待時間之後執行指定的硬體操作的部件。列出部分API函式名和功能:

1 esp_err_tesp_timer_init//初始化esp_timer庫
2 esp_err_tesp_timer_create//建立一個esp_timer例項esp_err_tesp_timer_start_once//啟動一個單次計時器
3 esp_err_tesp_timer_start_periodic//啟動一個週期計時器
4 esp_err_tesp_timer_stop//停止計時器
5 esp_err_tesp_timer_delete//刪除esp_timer例項

2.5 WatchDog

可以在一定時間內被複位的計數器。列出部分API函式名和功能:

1 esp_err_t esp_task_wdt_init//配置並初始化TWDT
2 esp_err_t esp_task_wdt_deinit//取消初始化任務WD定時器
3 esp_err_t esp_task_wdt_add//將任務訂閱到任務WD定時器
4 esp_err_t esp_task_wdt_delete//從任務WD計時器退訂任務

第三次作業已經列出PCNT、RMT、ADC和DAC的API函式介紹,此處略去。

三、設計模式及原則

  設計模式是一套總結,對於大型的軟體工程專案,設計模式可以增加程式碼的可重用性以及可維護性,讓程式碼更容易被理解,使程式碼真正工程化。根據設計模式可以完成的任務型別,可以把設計模式分為建立型模式(怎樣建立物件)、結構型模式(如何將類或物件按照某種佈局組成更大的結構)和行為型模式(程式在執行時複雜的流程控制)三種類型。由於此工程實踐是嵌入式層面設計,更多的是面向過程的C語言實現,所以面向物件的設計模式基本沒有實現,也無法提供相應例項進行說明。但運用了一些設計模式的思想,比如建造者模式:將一個複雜物件分解成多個相對簡單的部分,然後根據不同需要分別構建他們,最後構建成該複雜物件。

  設計原則,“SOLID”:開閉原則、Liskov替換原則、依賴倒置原則、單一職責原則、迪米特法則。這裡更多的體現的是Single Responsibility Principle,其可以降低類的複雜度,因為一個類只負責一項職責,其邏輯肯定要比負責多職責簡單得多;同時也可以提高類的內聚度。比如在ESP32中的VFS裡,分別對應檔案路徑、檔案系統以及檔案路徑和檔案系統之間的對應關係這三個類。其下是這些資料結構之間的關係:

四、軟體架構

4.1 軟體架構設計

  首先,我們常見的軟體架構有三種:第一種,三層架構:層次化架構是利用面向介面程式設計的原則將層次化的結構型設計模式作為軟體的主體結構。在嵌入式開發板的設計中,更多的是這種介面層——業務邏輯層——資料訪問層的三層架構模式。第二種,MVC即為Model-View-Controller(模型-檢視-控制器),其是一種涉及模式。M代表一個存取資料物件以及資料模型、V代表模型包含的資料的表達方式、C作用於模型和檢視上,控制資料流向模型物件,並在資料變化時更新檢視。控制器可以使檢視與模型分離開解耦合,是模型和檢視的橋樑。第三種,MVVM即為Model-View-ViewModel,和MVC模式一樣,只要目的是分離檢視和模型,有著以下一些優點:低耦合、可重用性、獨立開發和可測試性。

  其次,構建軟體架構模型的基本方法就是在不同層次上分解系統並抽象出其中的關鍵要素。常見的分解方法按照處理的事務型別來分類:功能、特徵、資料、併發、事件和物件。這些軟體架構風、層次分解方法和以上的設計模式沒有明顯的優劣之分,都有自己的適用領域。因此,需要分析採取最適合當前專案的軟體架構風格、分解方法和設計模式,以使專案得到最大化的收益。

  最後,需要描述關鍵要素之間的關係,軟體設計裡通過某些關鍵檢視來實現這一過程,即軟體架構的描述方法。為了理解軟體架構中的關鍵要素所表現出來的特徵,我們先來看一下軟體架構的風格和策略,然後再逐一分析軟體架構的檢視。

4.2 軟體架構的風格

  本專案是基於開發板的嵌入式開發,所以存在著較為複雜的軟體體系層次,僅僅從平面展開的角度進行模組化分解是不夠的,還需要從垂直縱深的角度講軟體單元按層次化組織,類似與OSI的七層模型,從使用者互動層到最後的硬體物理層。在ESP32的HTTP協議中,運用了客戶-服務風格的思想,它通常執行在TCP之上。它指定了客戶端可能傳送給伺服器什麼樣的訊息以及得到什麼樣的響應。請求和響應訊息的頭以ASCII碼形式給出;而訊息內容則具有一個類似MIME的格式。以下是客戶端和服務端的執行結果,可以看到在客戶-服務模式中,客戶是主動的,服務是被動的。客戶知道它像哪個服務發出請求,而服務卻不知道他正在為哪個客戶提供服務,甚至不知道正在為多少客戶提供服務。此種設計,降低了系統中客戶和服務構件之間耦合度,提高了服務構件的可重用性。

  同屬於軟體架構風格的還有:管道-過濾器、P2P、釋出-訂閱以及CRUD。

4.3 軟體架構的描述方法

  軟體架構模型是通過一組關鍵檢視來描述的,同一個軟體架構,由於選取的角度和抽象層次不同可以得到不同的檢視。一般來說,我們常說的幾種檢視有分解檢視、依賴檢視、泛化檢視、執行檢視、實現檢視、部署檢視和工作任務分配檢視。

4.3.1 分解檢視

  分解是構建軟體架構模型的關鍵步驟,分解檢視也是描述軟體架構模型的關鍵檢視,一般分解檢視呈現為較為明晰的分解結構特點。分解檢視用軟體模組勾劃出系統結構,往往會通過不同抽象層級的軟體模組形成層次化的結構。軟體架構代表了軟體系統的整體設計結構,它應該是所有這些檢視的集合。但我們不會將不同角度的這些檢視整合起來,因為不便於閱讀和更新。不過我們會有意識地將不同角度的檢視之間的對映關係和重疊部分了然於胸,從而深刻理解軟體架構內在的一致性和完整性,這就是系統概念原型。根據對開發板硬體模組的分類可以做出如下分解檢視:

4.3.2 依賴檢視

  依賴檢視展現了軟體模組之間的依賴關係。比如一個軟體模組A呼叫了另一個軟體模組B,那麼我們說軟體模組A直接依賴軟體模組B。如果一個軟體模組依賴另一個軟體模組產生的資料,那麼這兩個軟體模組也具有一定的依賴關係。它能幫助我們找到沒有依賴關係的軟體模組或子系統,以便獨立開發和測試,同時進一步根據依賴關係確定開發和測試軟體模組的先後次序。

4.3.3 泛化檢視

  泛化檢視展現了軟體模組之間的一般化或具體化的關係,典型的例子就是面向物件分析和設計方法中類之間的繼承關係。值得注意的是,採用物件組合替代繼承關係,並不會改變類之間的泛化特徵。因此泛化是指軟體模組之間的一般化或具體化的關係,不能侷限於繼承概念的應用。
  泛化檢視有助於描述軟體的抽象層次,從而便於軟體的擴充套件和維護。比如通過物件組合或繼承很容易形成新的軟體模組與原有的軟體架構相容。

4.3.4 執行檢視

  執行檢視展示了系統執行時的時序結構特點,比如流程圖、時序圖等。執行檢視中的每一個執行實體,一般稱為元件(Component),都是不同於其他元件的執行實體。如果有相同或相似的執行實體那麼就把它們合併成一個。執行實體可以最終分解到軟體的基本元素和軟體的基本結構,因而與軟體程式碼具有比較直接的對映關係。在設計與實現過程中,我們一般將執行檢視轉換為虛擬碼之後,再進一步轉換為實現程式碼。

  抽取部分硬體模組內的流程圖:

UART的原始碼流程圖:

DAC的例程流程圖:

Timer例程流程圖:

WatchDog例程流程圖:

4.3.5 實現檢視

  實現檢視是描述軟體架構與原始檔之間的對映關係。比如軟體架構的靜態結構以包圖或設計類圖的方式來描述,一般我們通過目錄和原始檔的命名來對應軟體架構中的包、類等靜態結構單元,這樣典型的實現檢視就可以由軟體專案的原始檔目錄樹來呈現。實現檢視有助於碼農在海量原始碼檔案中找到具體的某個軟體單元的實現。實現檢視與軟體架構的靜態結構之間對映關係越是對應的一致性高,越有利於軟體的維護,因此實現檢視是一種非常關鍵的架構檢視。

本專案的程式碼按照不同的硬體模組裝置進行編寫,不同模組間沒有具體的聯絡,同一模組內通過C語言面向過程的特點實現,只存在一個主void函式。所以,這裡我將程式碼的實現檢視轉化為不同硬體的實現檢視來理解:

4.3.6 部署檢視

  部署檢視是將執行實體和計算機資源建立對映關係。這裡的執行實體的粒度要與所部署的計算機資源相匹配,比如以程序作為執行實體那麼對應的計算機資源就是主機,這時應該描述程序對應主機所組成的網路拓撲結構,這樣可以清晰地呈現程序間的網路通訊和部署環境的網路結構特點。當然也可以用細粒度的執行實體對應處理器、儲存器等。部署檢視有助於設計人員分析一個設計的質量屬性,比如軟體處理網路高併發的能力、軟體對處理器的計算需求等。

4.3.7 工作分配檢視

  工作分配檢視將系統分解成可獨立完成的工作任務,以便分配給各專案團隊和成員。工作分配檢視有利於跟蹤不同專案團隊和成員的工作任務的進度,也有利於在個專案團隊和成員之間合理地分配和調整專案資源,甚至在專案計劃階段工作分配檢視對於進度規劃、專案評估和經費預算都能起到有益的作用。

五、執行環境和技術選型說明

  1)開發版說明:ESP-WROVER-KIT是一款基於ESP32無線網路和藍芽/藍芽低能耗(BLE)片上系統(SoC)的全功能開發板。該開發板相容基於Espressif系統的雙核無線雙模藍芽模組,包括 ESP-WROOM-32 和 ESP32-WROVER。ESP-WROVER-KIT 可滿足4.5MB記憶體和雙核240兆赫茲CPU的高效能要求,搭載先進的多協議通用序列匯流排橋(FTDI FT2232HL),允許開發人員直接通過 USB介面,使用 JTAG 對 ESP32 進行除錯,無需額外的 JTAG 偵錯程式。ESP-WROVER-KIT還提供板載高速微顯示卡介面、VGA攝像頭介面,以及3.2英寸SPI液晶面板和輸入/輸出擴充套件功能。旨在協助使用者快速開發物聯網 (IoT) 應用,可滿足使用者對 Wi-Fi、藍芽、低功耗等方面的要求。

  2)硬體資源:

(1)相容基於 ESP32 的雙核 Wi-Fi雙模藍芽模組

(2)車載高速微型SD卡

(3)精密 32.768KHz 晶體振盪器在深度睡眠模式下為晶片提供低功耗時鐘

(4)JTAG 介面

(5)VGA 攝像機介面

(6)3.2 英寸 SPI 液晶面板

(7)SPI 介面連線到外部快閃記憶體(PSRAM)

(8)I/O 擴充套件功能

(9)多協議USB網橋(FTDI FT2232HL)

(10)重置和啟動使用者按鈕

(11)USB介面作為板卡的電源和PC機與ESP32模組之間的通訊介面

  3)軟體資源

(1)BootLoader

(2)FreeRTOS

(3)ESP-IDF

六、系統概念原型的核心工作機制

  概念是人對能代表某種事物或發展過程的特點及意義所形成的思維結論,概念原型是一種虛擬化的、理想化的軟體產品形式。也就是說,概念原型 = 用例 + 資料模型。

  軟體架構代表了軟體系統的整體設計結構,它應該是所有這些檢視的集合。但我們不會將不同角度的這些檢視整合起來,因為不便於閱讀和更新。不過我們會有意識地將不同角度的檢視之間的對映關係和重疊部分了然於胸,從而深刻理解軟體架構內在的一致性和完整性,這就是系統概念原型。

七、總結

  這次的作業是基於軟體設計的一個軟體系統設計方案,由於個人的專案是嵌入式開發且面向過程的程式設計,在總結軟體結構特點時,由於學習深度和實力不限,很難找到對應的概念匹配。所以,就根據個人的理解剖析硬體設計裡體現的軟體思想來繼續編寫。也希望其他大佬多多指點和建議。

八、參考資料

https://gitee.com/mengning997/se/blob/master/ppt/%E8%BD%AF%E4%BB%B6%E7%A7%91%E5%AD%A6%E5%9F%BA%E7%A1%80%E6%A6%82%E8%AE%BA.pptx

SoftwareEngineering:TheoryandPractice(FourthEdition),ShariLawrencePfleeger,JoanneM.Atlee

https://github.com/fwing1987/MyVue

https://vuejs.org

http://c.biancheng.net/design_pattern/