Try   HackMD

Access Device File on Linux

本篇用來記錄透過cpp實現在userspace存取Linux上的Device file, 及相關Lib的使用

讀取Linux上的eeprom

#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

int file = open("/sys/bus/i2c/devices/6-0054/eeprom", O_RDONLY);

透過open回傳File Descriptor給其他需要存取檔案的函式使用,後面加上O_RDONLY表示使用唯讀的方式做開啟,另外還有O_WRONLYO_RDWR可使用

open 與開啟方式是由fctl.h提供


lseek

auto result = lseek(file, 0x0000, SEEK_SET);

透過lseek把讀寫位置從檔案的開始+offset個位置,return 目前的偏移量,SEEK_SET表示從檔案的開始。

lseek 由unistd.h提供
SEEK位置由fcnt.h提供
SEEK_CUR -> 檔案目前往後+offset
SEEK_END -> 檔案結尾往後+offset


read

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中

read 由unistd.h 提供
read(int _fd, void _buf, size_t nbytes)

獲得EEPROMSize

此範例使用stdio.h的fopen、fseek、ftell

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數

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