前面一篇博文《嵌入式軟件架構設計之分層設計》給你們分享了程序分層設計的一些我的觀點。裏面有提到接口統一規範的問題,下面這篇博文詳細闡述一下關於代碼可移植性的問題。代碼可移植性很是重要!在這裏有的人很納悶,有人會問:除了彙編語言的移植性不好之外,c語言,c++,java等其餘高級語言的移植性不是都很棒的麼。毋庸置疑,c語言的移植性是很是好。但本文不是在探討一段編程語言的移植性問題,要探討的是:在不一樣的嵌入式平臺上,如何提升開發嵌入式產品的效率問題。換一種表達方式:如何提升嵌入式軟件平臺之間的可移植性。java
在探討以前先拋出一個問題:如何才能使開發的應用程序運行在不一樣的硬件平臺上?這裏所指的應用程序不是指pc端的應用也不是指的android,ios等平臺的應用。而是指的是其餘嵌入式平臺的應用,他們更多的是c語言實現。咱們都知道windows平臺也好仍是ios,android平臺也罷,他們的應用是不一樣的編程語言實現的,可是他們有一個共同的特色:給應用開發人員提供標準的sdk接口。正是這些標準的接口使得應用開發和硬件以及底層相分離。大大提升了應用程序的可移植性。linux
目前來看,嵌入式產品若不是android系統,是沒有統一的接口規範的。公司在開發設計某款嵌入式產品時,涉及到以下內容:硬件平臺選型,軟件平臺選型,底層軟件開發,應用軟件開發。底層軟件和硬件是緊密聯繫在一塊兒的,而應用軟件能夠作到與硬件平臺無關。要作到無關就得定義統一的接口規範。讓應用程序調用接口規範規定的接口,底層軟件根據不一樣的平臺封裝不一樣的程序來實現其接口功能。如此大大提升應用程序不一樣硬件平臺的可移植性。這樣作也規範了編程,增長了程序的可讀性。android
下面以文件操做爲例ios
1.本模塊相關宏定義c++
//本模塊相關宏定義以及結構定義以下: // 錯誤碼定義 #define FILE_EXIST 1 #define FILE_NOEXIST 2 #define MEM_OVERFLOW 3 #define TOO_MANY_FILES 4 #define INVALID_HANDLE 5 #define INVALID_MODE 6 #define FILE_NOT_OPENED 8 #define FILE_OPENED 9 #define END_OVERFLOW 10 #define TOP_OVERFLOW 11 #define NO_PERMISSION 12 #define FS_CORRUPT 13 //以上錯誤碼與標準linux的錯誤碼errno有差別,對於Linux系統的機型,錯誤碼保留linux標準的errno定義。 // 文件打開模式,可以使用"或"組合 #ifndef O_RDONLY #define O_RDONLY 00 #endif #ifndef O_WRONLY #define O_WRONLY 01 #endif #ifndef O_RDWR #define O_RDWR 02 #endif #ifndef O_NONBLOCK #define O_NONBLOCK 04000 #endif #ifndef O_CREAT #define O_CREAT 0100 #endif // 文件定位起點 #ifndef SEEK_SET #define SEEK_SET 0 #endif #ifndef SEEK_CUR #define SEEK_CUR 1 #endif #ifndef SEEK_END #define SEEK_END 2 #endif // 文件信息 typedef struct { char fid; char attr; char type; char name[17]; int length; } FILE_INFO;
2.接口函數規範說明編程
2.1 dev_FileOpenwindows
原型:架構 |
int dev_FileOpen(const char *FileName, int Mode);編程語言 |
|||
功能:ide |
打開本應用所屬的文件 |
|||
參數: |
FileName(輸入) |
1-16Bytes |
文件名,最多能夠是16個字符,以‘\x00’結尾,超過16個字符的只取前16個。 |
|
Mode(輸入) |
O_CREAT |
0100 |
||
O_RDWR |
02 |
文件打開方式,O_RDWR表示打開文件用於讀/寫, |
||
返回: |
[0,255] |
成功,返回句柄號 |
||
-1 |
失敗,錯誤碼放在errno中 |
|||
註釋: |
若是以O_CREATE | O_RDWR的方式打開文件,若文件已存在,則以O_RDWR的方式打開,不然建立該文件。已打開的文件能夠重複打開,每次打開後,文件指針移到文件開頭。 錯誤碼介紹: INVALID_MODE mode不爲O_RDWR/O_CREATE FILE_NOEXIST 文件不存在 FILE_EXIST 當文件存在時以O_CREATE的方式打開 MEM_OVERFLOW空間不足 TOO_MANY_FILES 文件句柄太多,超過255,沒法建立新文件 FILE_OPENED 文件已打開 |
|||
示例: |
打開文件」Demo.bin」, 若是不存在該文件,則建立該文件。 int Ret = 0; Ret = fileOpen(「Demo.bin」,O_RDWR); // 以讀寫方式打開該文件 if(Ret < 0) // 該文件不存在,則從新建立 { Ret = fileOpen(「Demo.bin」, O_CREAT); if(Ret < 0) { return Ret; // 建立失敗,則返回錯誤碼 } } ………………… // 對這個文件進行其餘的讀寫操做等 |
2.2 dev_FileSeek
原型: |
int dev_FileSeek(int FileID, int Offset, int Whence); |
|||
功能: |
對打開的文件指針進行定位 |
|||
參數: |
FileID(輸入) |
[0,255] |
文件句柄號,從打開文件得到的返回句柄 |
|
Offset(輸入) |
從Whence指定的位置到要移到的位置的字節數(有符號值) |
|||
Whence(輸入) |
SEEK_SET |
0 |
表示從文件頭開始 |
|
SEEK_CUR |
1 |
從當前文件指針開始 |
||
SEEK_END |
2 |
從文件尾開始。 |
||
返回: |
>=0 |
成功, 返回的數值是文件當前指針相對文件頭的位置 |
||
-1 |
失敗,參數錯誤或偏移目標超出文件範圍,錯誤碼放在errno中。 |
|||
註釋: |
錯誤碼介紹: INVALID_FILEID無效的文件句柄 FILE_NOT_OPENED 文件未打開 END_OVERFLOW 後移時超出文件長度的偏移 TOP_OVERFLOW 前移時出錯 |
|||
示例: |
調用該函數前,必須先確認指定文件已經被正確打開了: fd = fileOpen(「filename」, O_RDWR); 1、定位到文件的第2個字節位置: Ret = fileSeek(fd, 2, SEEK_SET); 2、定位到文件的倒數第2個字節位置: Ret = fileSeek(fd, -2, SEEK_END); 3、定位當前位置的後面第2個字節處: Ret = fileSeek(fd, 2, SEEK_CUR); |
2.3 dev_FileRead
原型: |
int dev_FileRead(int FileID, void *DataBuf, int Len); |
||
功能: |
從文件的當前定位位置開始讀取文件數據 |
||
參數: |
FileID(輸入) |
[0,255] |
文件句柄號,從打開文件得到的返回句柄 |
DataBuf(輸出) |
應用指定的用來存放讀取數據的緩衝區 |
||
Len(輸入) |
指望讀取的數據字節數。 |
||
返回: |
>=0 |
讀取成功,返回實際讀到的字節數。 |
|
-1 |
失敗,錯誤碼放在errno中 |
||
註釋: |
讀取後文件指針位置將移動到讀取後的位置 錯誤碼介紹: FILE_NOT_OPENED文件未打開 INVALID_FILEID無效的文件句柄 |
||
示例: |
調用該函數以前,先調用fileOpen打開指定的文件: fd = fileOpen(「Filename」, O_CREAT|O_RDWR);
1、從文件起始處讀取16字節 Ret = fileSeek(fd, 0, SEEK_SET); Ret = fileRead(fd, Buff, 16);
2、從當前光標位置處開始讀取16字節: Ret = fileSeek(fd, 0, SEEK_CUR); Ret = fileRead(fd, Buff, 16);
3、讀取文件的最後16個字節 Ret = fileSeek(fd, -16, SEEK_END); Ret = fileRead(fd, Buff, 16); |
2.4 dev_FileWrite
原型: |
int dev_FileWrite(int FileID, const void *DataBuf, int Len); |
||
功能: |
從文件的當前定位位置開始寫入數據 |
||
參數: |
FileID(輸入) |
[0,255] |
文件句柄號,從打開文件得到的返回句柄 |
DataBuf(輸入) |
應用指定的存放寫入數據的緩衝區 |
||
Len(輸入) |
須要寫入數據的字節數。 |
||
返回: |
>=0 |
寫入成功,返回實際寫入的字節數。 |
|
-1 |
失敗,錯誤碼放在errno中 |
||
註釋: |
寫入後,文件指針位置將移動到寫入後的位置 錯誤碼介紹: INVALID_FILEID 無效的文件句柄 FILE_NOT_OPENED 文件未打開 MEM_OVERFLOW 空間不足或文件句柄太多 |
||
示例: |
調用該函數以前,必須先調用fileOpen打開指定的文件: fd = fileOpen(「filename」, O_RDWR|O_CREAT);
1、修改文件的頭16個字節: Ret = fileSeek(fd, 0, SEEK_SET); Ret = fileWrite(fd, Buff, 16);
2、從當前光標處開始寫入16字節: Ret = fileSeek(fd, 0, SEEK_CUR); Ret = fileWrite(fd, Buff, 16);
3、從文件結束處再寫入16字節: Ret = fileSeek(fd, 0, SEEK_END); Ret = fileWrite(fd, Buff, 16); |
2.5 dev_FileTruncate
原型: |
int dev_FileTruncate(int FileID, int Len); |
||
功能: |
截短文件 |
||
參數: |
FileID(輸入) |
[0,255] |
文件句柄號,從打開文件得到的返回句柄 |
Len(輸入) |
從文件頭保留的文件數據長度。 |
||
返回: |
0 |
成功截斷。 |
|
-1 |
失敗,錯誤碼放在errno中。 |
||
註釋: |
該函數將文件截斷爲Len長度,原文件中從Len到結尾的內容全被截去。文件指針移至截短後的文件的最後。 錯誤碼介紹: NO_FILESYS文件系統未創建 INVALID_FILEID 無效的文件句柄 FILE_NOT_OPENED 文件未打開 TOP_OVERFLOW 長度小於0 END_OVERFLOW 長度超出文件長度 |
||
示例: |
只保留指定文件的前256字節內容: fd = fileOpen(「filename」, O_RDWR);
Ret = fileTruncate(fd, 256); |
2.6 dev_FileClose
原型: |
int dev_FileClose(int FileID); |
||
功能: |
關閉已打開的文件 |
||
參數: |
FileID(輸入) |
[0,255] |
文件句柄號,從打開文件得到的返回句柄 |
返回: |
0 |
成功關閉文件 |
|
-1 |
失敗,錯誤碼放在errno中。 |
||
註釋: |
錯誤碼介紹: INVALID_FILEID無效的文件句柄 |
||
示例: |
先打開文件: fd = fileOpen(「filename」, O_RDWR | O_CREAT); ………………… // 文件相關處理 關閉文件: Ret = fileClose(fd); |
2.7 dev_FileRemove
原型: |
|||
功能: |
刪除文件 |
||
參數: |
FileName(輸入) |
1-16Bytes |
文件名,最多能夠是16個字符,以‘\x00’結尾,超過16個字符的只取前16個。 |
返回: |
0 |
成功 |
|
-1 |
失敗,錯誤碼放在errno中。 |
||
註釋: |
錯誤碼介紹: FILE_OPENED 文件已打開 FILE_NOEXIST 文件不存在 |
||
示例: |
刪除指定文件: Ret = fileRemove(「filename」); |
2.8 dev_FileSize
原型: |
int dev_FileSize(const char *FileName); |
||
參數: |
FileName(輸入) |
1-16Bytes |
文件名,最多能夠是16個字符,以‘\x00’結尾,超過16個字符的只取前16個。 |
返回: |
>=0 |
文件的大小 |
|
-1 |
失敗,錯誤碼放在errno中。 |
||
註釋: |
錯誤碼介紹: FILE_NOEXIST 文件不存在 |
||
示例: |
fileLen = fileSize(「filename」); // 查詢文件大小 |
2.9 dev_FileExist
原型: |
int dev_FileExist(const char *FileName); |
||
功能: |
判斷文件是否存在 |
||
參數: |
FileName(輸入) |
1-16Bytes |
文件名,最多能夠是16個字符,以‘\x00’結尾,超過16個字符的只取前16個。 |
返回: |
[0,255] |
文件序號。 |
|
-1 |
在當前應用中沒有指定的文件 |
||
註釋: |
無 |
||
示例: |
判斷某個文件是否存在,如存在,則獲取其大小: Ret = fileExist(「filename」); if(Ret >= 0) { fileLen = fileSize(「filename」); } |
2.10 dev_FileRename
原型: |
int dev_FileRename(const char *OldFileName, const char *NewFileName); |
||
功能: |
修改屬於本應用的數據文件文件名 |
||
參數: |
OldFileName(輸入) |
1-16Bytes |
原文件名,最多能夠是16個字符,以‘\x00’結尾,超過16個字符的只取前16個。 |
NewFileName(輸入) |
1-16Bytes |
新文件名,最多能夠是16個字符,以‘\x00’結尾,超過16個字符的只取前16個。 |
|
返回: |
0 |
成功 |
|
-1 |
失敗,錯誤碼放在errno中。 |
||
註釋: |
錯誤碼介紹: FILE_OPENED 文件已打開 FILE_NOEXIST 文件不存在 FILE_EXIST 新文件已經存在 |
||
示例: |
2.11 dev_FileFreeSpace
原型: |
int dev_FileFreeSpace(void); |
功能: |
返回文件系統剩餘可寫的字節數 |
參數: |
無 |
返回: |
返回文件系統總共剩餘的空間大小(字節數) |
註釋: |
無 |
示例: |
判斷文件系統還有多少剩餘空間: FreeLen = fileFreeSpace(); |
2.12 dev_MntSDCard
原型: |
int dev_MntSDCard(const char *TargetDir, int Mode); |
||
功能: |
掛載SD卡。 |
||
參數: |
TargetDir(輸入) |
指定的掛載SD卡的目錄,默認爲"/mnt/sdcard/"。若爲NULL則SD卡自動掛載到"/mnt/sdcard/"目錄。 |
|
Mode(輸入) |
TRUE |
掛載SD卡 |
|
FALSE |
卸載SD卡 |
||
返回: |
0 |
掛載成功 |
|
-1 |
掛載失敗 |
||
註釋: |
應用層不須要關心掛載的設備名和filesystem類型。 掛載SD卡命令:mount -t vfat /dev/sdd1 /mnt/sdcard |
2.13. dev_MntUSBDisk
原型: |
int dev_MntUSBDisk(const char *TargetDir, int Mode); |
||
功能: |
掛載U盤。 |
||
參數: |
TargetDir(輸入) |
指定的掛載U盤的目錄,默認爲"/mnt/usb/"。若爲NULL則U盤自動掛載到"/mnt/usb/"目錄。 |
|
Mode(輸入) |
TRUE |
掛載U盤 |
|
FALSE |
卸載U盤 |
||
返回: |
0 |
掛載成功 |
|
-1 |
掛載失敗 |
||
註釋: |
應用層不須要關心掛載的設備名和filesystem類型。 掛載U盤命令:mount -t vfat /dev/sda1 /mnt/usb |
統一接口後,凡是對文件的操做,應用程序或者SDK層都只能調用這些接口,這樣無論是linux平臺仍是其餘嵌入式操做系統或非操做系統平臺,應用程序對文件的操做的接口函數都是同樣的了,這樣就作到了應用程序不一樣平臺的兼容性。