---
# System prepended metadata

title: Access Device File on Linux
tags: [C/C++, Linux]

---

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可指定開啟的權限
 