嵌入式項目中,軟件是一個不斷迭代的過程,需要考慮各種兼容性。之前我們的項目,因為這方面考慮得比較少,導致項目中后期開發(fā)起來很被動。
項目系統(tǒng)總體設計階段,應盡可能地考慮到未來可以遇見的情況,覆蓋到盡可能多的業(yè)務擴展。項目雖然分階段開發(fā),各個階段完成的功能都不一樣,總體設計要指向最終的需求。
數據兼容性
1、協(xié)議制定
制定的協(xié)議要滿足整個項目所有數據的交互。
比如:
這里的 ID 設置為 1 個字節(jié),可能有一定的風險。后面功能加著加著,可能 1 個字節(jié)的 ID 滿足不了,就得改協(xié)議。盡管可能滿足了某個項目的需求,但萬一之后其它項目也用了這一套代碼,但是 1 個字節(jié)的 ID 滿足不了,又得改代碼。這里設置 2 字節(jié)可能會好一點,基本上能滿足絕大部分情況的使用。
不一定為了覆蓋范圍更廣而設置 4 字節(jié),這樣可能有點冗余。很多情況都有一個平衡點,需要自己權衡。
Length字段只設置了 1 個字節(jié),可能也有一定的奉獻。后面功能中如果有發(fā)較大的數據,可能要分好多包發(fā),原本可以發(fā)得很快,被這里限制死了。到時候想要提速,就得改協(xié)議。
之前項目里,幾塊板間的通信都用同一套協(xié)議。但后期發(fā)現該協(xié)議滿足不了新需求,但為了不影響到前面的數據,又搞了一套協(xié)議。導致項目里有兩套差不多一樣的協(xié)議處理代碼。
協(xié)議應該是項目一開始考慮好、制定好,整個項目開發(fā)期間,都不應該再做改動。
2、數據添加
后面新增的數據,不應該插入現有的數據中,應該單獨增加一個數據ID。
比如:
現有的數據中,有一條數據叫做設備信息的數據,設備信息里包含了:設備IP、設備Mac。這個數據會顯示在手機APP上。對應的 C 語言代碼:
#defineMSG_ID_DEV_INFO0x0001 typedefstruct_dev_info { chardev_ip[IP_MAX_LEN]; chardev_mac[MAC_MAX_LEN]; }dev_info_t;
假如后面需要再顯示一個設備的sn,這個數據我們應該加在哪里?
如果是項目前中期,這時候還是在開發(fā)階段,我們可以隨意修改。因為設備sn也是設備信息的一部分,可以直接在設備信息這個數據里添加會比較合理:
#defineMSG_ID_DEV_INFO0x0001 typedefstruct_dev_info { chardev_ip[IP_MAX_LEN]; chardev_mac[MAC_MAX_LEN]; chardev_sn[SN_MAX_LEN]; }dev_info_t;
如果是產品已經在市場上流通,這時候這么加的話,軟件兼容性就不太好。因為假如你的手機APP版本與設備版本不匹配,原有的設備IP及設備MAC這兩個設備信息可能都顯示不出來,因為我們這么一改,破壞了原有的數據結構,而手機APP按照原來的數據來做解析的,會解析不過。
這時候可以這么來加:
#defineMSG_ID_DEV_INFO0x0001 #defineMSG_ID_DEV_SN0x0002 typedefstruct_dev_info { chardev_ip[IP_MAX_LEN]; chardev_mac[MAC_MAX_LEN]; }dev_info_t; typedefstruct_dev_sn { chardev_sn[SN_MAX_LEN]; }dev_sn_t;
這樣,哪怕手機APP版本與設備版本沒有對應上,原來的數據還是能正常顯示的。當然,最好的情況當然是在開發(fā)階段就合理地設計好。不然,像這種情況,只能犧牲一些程序可讀性來換取程序兼容性了。這會讓后面看代碼的人覺得很奇怪,你這個sn不也是數據設備信息嗎,怎么還單獨給一個ID。后面接手這個代碼的人可能就會把這一塊代碼給改了。
溫馨提示:在沒有完全弄懂維護項目的代碼為什么這么實現的情況下,能正常在跑的程序還是別亂動得好,哪怕你覺得這是屎山代碼。否則可能會出大問題。要么等到軟件重構時再修改,要么就繼續(xù)打補丁。
3、數據刪除
如果是刪除本模塊內部自己使用的數據,你想怎么刪就怎么刪。
如果是刪除與其它模塊進行交互的數據,這就不能這么隨意了。比如,請求、應答的方式。應答端給請求端返回的數據是不能隨意刪的,如果要刪,一定要確保請求端已經沒有請求數據的需求,并且已經去掉相關代碼時,這時候應答端才去刪數據,否則還是留著吧。
4、數據修改
其實數據定了,為了保證軟件兼容性,應該是要禁止修改的。
如果一定要修改,可以先增加一條新數據,后面慢慢切為新數據、刪除舊數據。
接口兼容性
正在使用的接口,應該盡量不要修改。如果要修改,一定不要影響之前的功能。
之前就有遇到類似的情況。舉個例子:
typedefenum_sys_status { SYS_STATUS_IDLE, SYS_STATUS_RUNNING, SYS_STATUS_STOP, }sys_status_t; staticsys_status_tg_sys_status; sys_status_tget_sys_status(void) { returng_sys_status; }
這里的系統(tǒng)狀態(tài)是要顯示在手機APP上的,不同的狀態(tài)顯示不同的圖標。后面要新增一個狀態(tài),結果數據提供者這么改
typedefenum_sys_status { SYS_STATUS_IDLE, SYS_STATUS_NEW_STATUS, SYS_STATUS_RUNNING, SYS_STATUS_STOP, }sys_status_t; staticsys_status_tg_sys_status; sys_status_tget_sys_status(void) { returng_sys_status; }
接口提供者把新增的數據插入了中間,影響了枚舉原有的順序。結果手機APP上圖標顯示亂了。
影響到接口的修改,要保證原有的數據不受影響。
系統(tǒng)兼容性
在軟件升級過程中,需要考慮軟件所依賴的其他系統(tǒng)組件是否發(fā)生變化,以確保升級后軟件能夠正常運行,不會影響其他系統(tǒng)組件的正常運行。如果其他系統(tǒng)組件發(fā)生變化,則需要進行相關測試和文檔更新,以確保整個系統(tǒng)能夠正常運行。
另外隨著項目的迭代,這一套代碼有可能運行于不同的系統(tǒng)不同的芯片平臺。
比如,我們嵌入式Linux項目,有些項目里會用到一些第三方庫,這時候可能會編譯成動態(tài)庫的形式。要考慮升級的時候能不能升級動態(tài)庫。如果不能,就得把依賴的庫一起編譯到可執(zhí)行程序里。
另外,如果使用動態(tài)庫,之后產品軟硬件迭代換了一個芯片平臺的話,我們就需要重新交叉編譯一次所依賴的庫。如果為了保證這一塊的兼容性,也可以考慮把所依賴的庫與用戶代碼一起編譯。
當然,這個根據實際情況進行權衡取舍。如果依賴的庫很多,一起編譯到可執(zhí)行程序里,導致可執(zhí)行程序很大,到時候更新也不好更新。
功能兼容性
涉及到功能的添加的,盡量不要影響到之前已開發(fā)的功能。不然也會增加用戶對產品的學習成本。比如某些指示燈在前一個版本的快閃、慢閃代表什么意思,這個在之后就盡量不要去修改了,不然用戶又得重新理解。
性能兼容性
在軟件升級過程中,需要考慮軟件的性能是否發(fā)生變化,以確保升級后軟件的性能仍然能夠滿足用戶需求。如果軟件的性能發(fā)生變化,則需要進行相關測試和優(yōu)化,以確保軟件能夠正常運行,并且能夠滿足用戶的性能需求。
比如,原來正常升級需要3分鐘,某個版本之后升級變成了6分鐘,升級效率變差了。
安全兼容性
在軟件升級過程中,需要考慮軟件的安全性是否得到加強,以確保升級后軟件的安全性能夠得到保障,不會出現新的安全風險。如果軟件的安全性得到加強,則需要進行相關測試和文檔更新,以確保軟件能夠正常運行,并且能夠保障用戶的安全。
審核編輯:黃飛
-
嵌入式軟件
+關注
關注
4文章
239瀏覽量
26598
原文標題:不容忽視的嵌入式軟件兼容性問題
文章出處:【微信號:Linux大陸,微信公眾號:Linux大陸】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
相關推薦
評論