組み込み技術を向上したい!!

でも組み込み以外にも手を出し始めました・・・

mmap (C, Python exchange data)

毎度のことだけど、ほぼ個人的メモなので、もし参考にする人がいたら注意してね!!
意外と見てくれている人がいるみたいなので。

 

Linuxなどまともに触れたことがなく、OSと言ってもFreeRTOS程度のものしかいじったことがなかった。。。

RaspberryPiで遊んでいたときに、"PythonのプログラムとCのプログラムで変数を共有できたら楽なのになぁ"という問題に直面した。

いろいろ調べた結果mmapという関数(機能)を使えば、イメージした動作が実現できそうだ。

CとPythonの両方から一つのファイル(メモリ)をリードライトすると何となく危険な気がしたので、今回はPythonからCへ情報を提供するファイルtoc.datとCからPythonへ情報を提供するファイルtopy.datの二つを使って実験してみた。。。

まずはPython

   
        #---- Cにデータを提供するファイルについて ----
        toC_File = open(toc.dat, 'r+')
     
        toC_No = toC_File.fileno()
        #ここのlengthは重要で、ファイルサイズの値と一致させないといけない
        toC_Map = mmap.mmap(toC_No,length,access=mmap.ACCESS_WRITE) 
        toC_File.seek(0)
        write_str = "0123456789"          
        print len(write_str) #書き込む文字列長をコンソール上に表示して確認してみる
          
        toC_Map.write(write_str)
        toC_File.close()

        #---- Cからデータをもらうファイルについて ----
        toPy_File = open(topy.dat,'r')
        #ここのdatasizeも重要。ファイルサイズの値と一致させないといけない
        toPy_Map = mmap.mmap(toPy_File.fileno(), datasize, access=mmap.ACCESS_READ) 
        toPy_File.seek(0)
        # 想定したデータがやり取りできているか確認するためにはreadして中身をみるといい
        param = toPy_Map.read(3)
        #print param
        toPy_File.close()

そしてC側

  int    topy_fd, toc_fd;
  long   topy_size, topy_pagesize, toc_size, toc_pagesize;
  char   *topy_pc, *toc_pc; // topy.dat用データポインタとtoc.dat用データポインタ
  // 想定されるデータ量を保持したファイルをもともと作っておくと良さげ
  // 今回はその部分は省略
  if((topy_fd=open(topy.dat,O_RDWR|O_CREAT,0666))==-1) {
    perror("open");
    exit(-1);
  } 

  topy_pagesize=sysconf(_SC_PAGE_SIZE);
  // DATASIZEはpythonで使ったdatasizeと同じ値で、必要最低限が良さそう。
  topy_size=(DATASIZE*sizeof(char)/topy_pagesize+1)*topy_pagesize;
  if(lseek(topy_fd,0,SEEK_SET) < 0){
    perror("lseek");
    exit(-1);
  }

  topy_pc=(char*)mmap(0,topy_size,PROT_READ|PROT_WRITE,MAP_SHARED,topy_fd,0);
  if((int)topy_pc == -1){
    perror("mmap");
    exit(-1);
  }
  // あとはtopy_pcを使って値を入れていけばOK.python側で参照できるはず。
  close(topy_fd);
  //----------------------------------------------------
  
  if((toc_fd=open(toc.dat,O_RDWR))== -1){
    perror("open");
    exit(-1);
  }
  
  toc_pagesize=sysconf(_SC_PAGE_SIZE);
  // ここのLENGTHはpythonで使ったlengthと同じ値で、必要最低限が良さそう。
  toc_size=(LENGTH*sizeof(char)/toc_pagesize+1)*toc_pagesize;

  if(lseek(toc_fd,0,SEEK_SET)<0){
    perror("lseek");
    exit(-1);
  }
  
  toc_pc=(char*)mmap(0,toc_size,PROT_READ,MAP_SHARED,toc_fd,0);
  if ( toc_pc == MAP_FAILED ) {
    printf("Mmap Error!!\n");
  }
  // あとはtoc_pcを使ってpythonからのデータを確認すればOK.
  close(toc_fd);

topy_pcとtoc_pcのポインタをグローバルにしていろいろいじってデータのやりとりをすると思いのほかうまくいった。常時走らせるプログラムでない場合はmunmapとかをうまく使ってやったほうが良さげ。