Access Device File on Linux
===
本篇用來記錄透過cpp實現在userspace存取Linux上的Device file, 及相關Lib的使用
讀取Linux上的eeprom
---
```cpp=
#include <iostream>
#include <array>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/i2c.h>
#include <unistd.h>
int main(){
int file = open("/sys/bus/i2c/devices/6-0054/eeprom", O_RDONLY);
auto result = lseek(file, 0x0000, SEEK_SET);
if (result < 0)
{
std::cout << "fail to seek\n";
return -1;
}
else
{
std::cout << "succeed to seek\n";
}
std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> blockData;
// I2C_SMBUS_BLOCK_MAX from linux/i2c.h
auto data = read(file, blockData.data(), 0x8);
for (size_t i = 0; i < 8; i++)
{
std::cout << unsigned(blockData[i]) << std::endl; //轉成unsigned並顯示
}
return 0;
}
```
### open
```cpp=11
int file = open("/sys/bus/i2c/devices/6-0054/eeprom", O_RDONLY);
```
透過**open**回傳File Descriptor給其他需要存取檔案的函式使用,後面加上**O_RDONLY**表示使用唯讀的方式做開啟,另外還有**O_WRONLY**、**O_RDWR**可使用
:::info
open 與開啟方式是由fctl.h提供
:::
---
### lseek
```cpp=12
auto result = lseek(file, 0x0000, SEEK_SET);
```
透過**lseek**把讀寫位置從檔案的**開始+offset**個位置,return 目前的偏移量,**SEEK_SET**表示從檔案的開始。
:::info
lseek 由unistd.h提供
SEEK位置由fcnt.h提供
SEEK_CUR -> 檔案目前往後+offset
SEEK_END -> 檔案結尾往後+offset
:::
---
### read
```cpp=24
std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> blockData;
auto data = read(file, blockData.data(), 0x8);
```
建立一個uint8_t型態,長度為``I2C_SMBUS_BLOCK_MAX``的Array
並使用**read**讀取0x08個bytes的資料到blockData中
:::info
read 由unistd.h 提供
read(int _fd, void _buf, size_t nbytes)
:::
獲得EEPROMSize
---
此範例使用stdio.h的fopen、fseek、ftell
```cpp=
int checkEepromSize(std::string path)
{
FILE *pFile;
pFile = fopen("/sys/bus/i2c/devices/6-0054/eeprom", "rd");
auto result = fseek(pFile, 0, SEEK_END);
unsigned long len = (unsigned long)ftell(pFile);
std::cout << "file len = " << len << std::endl;
}
```
**流程:**
1. fopen開啟檔案
2. fseek移動檔案游標位置到最後
3. ftell獲得從檔案頭到目前位置的byte數
:::info
fopen, fseek, ftell 由stdio.h提供
:::
討論
---
**open 與 fopen有何差異?**
> 1. open 是較低階的IO,UNIX的system call,return **file descriptor**
> 2. fopen 是標準C定義的函數,底層實作也是會call到open,return 一個指向檔案的**ptr**
> 3. open無緩衝,fopen有緩衝(buffer);在使用read時只分配2K buffer若檔案超過,則須執行多次system call讀取資料,fread可以直接指定buffer大小只需要執行一次從HD讀出
> 4. 由於open是較低級別的IO,可更接近系統可以存取到fopen無法訪問的訊息
> 5. open可指定開啟的權限