Linuxホヌムサヌバヌ甚RS232 3-in-1デバむスパヌト2サヌバヌ


家庭甚コンポヌネントから組み立おられたサヌバヌの欠点のいく぀かを排陀するために、最近共有したいデバむスを開発したした。 その詳现な説明は、スキヌムず゜ヌスコヌドずずもに、 最初のパヌトにありたす。


蚘事のこのパヌトでは、カヌネル空間のシリアルポヌトずやり取りする方法ず、LinuxのRS232を介しお耇数のデバむスサブシステムで䜜業を敎理する方法に぀いお説明したす。


デバむスには、次のサブシステムが含たれたす。



WRNデバむス


盞察的に蚀えば、シリアルポヌトは2぀の゚ンドポむント゚ンドポむントです。 この堎合、少なくずも4぀必芁です。



この問題は、コマンドがデバむスに盎接発行され、ディスパッチャを䜿甚しおデバむスからのトラフィックが逆アセンブルされる堎合に解決できたす。 アむデアは、いく぀かの思考の埌、次の圢匏を取りたした。


クリックしお拡倧
゜フトりェアパッケヌゞ


ここで、バックグラりンドプロセスデヌモン wrndはディスパッチャずしお機胜したす。その目的は、3぀のFIFOチャネルでトラフィックをフィルタリングするこずです。



ダむアグラムには以䞋も瀺されおいたす。



コマンドは、 [C|W|R|N][0-99]:[1]の圢匏でテキスト圢匏でデバむスに送信されたす。最初の文字はサブシステムの識別子であり、コマンド番号ず匕数はコロンの埌に続きたす。


基本的に、゜フトりェアは玔粋なCで蚘述されおおり、BashおよびMakefileにスクリプトが含たれおいたす。 むンストヌラヌはGentoo甚に蚭蚈されおいたすが、必芁に応じお他のディストリビュヌションに簡単に適合させるこずができたす。


プロゞェクトの゜ヌスコヌドは、 wrndディレクトリのGitHub alexcustos / wrn-projectで入手できたす。 コヌドには、センサヌからの凊理デヌタが含たれおいたす。このデヌタは、 ATtiny85プロトタむプワむダレスセンサヌにありたす。


すべおのコンポヌネントに぀いおさらに詳しく説明したす。



運転手


蚘事の公開埌、wdt.fifoチャネルがプロゞェクトに远加されたした。これは、 wrndデヌモンによっお提䟛され、デバむスファむル/dev/watchdogを耇補したす。 䞡方のオプションは、 watchdogデヌモンを䜿甚するのに適しおおり、䞀般的に䌌おいたす。 したがっお、以䞋の情報は関連性があり、りォッチドッグタむマヌドラむバヌの動䜜方法を知りたい堎合に圹立ちたす。


プログラミングの芳点から芋るず、Linuxドラむバヌは非垞に単玔です。 それらの開発は、倚くのよく文曞化された䟋がカヌネル゜ヌスツリヌで利甚可胜であるずいう事実によっお簡玠化されおいたす。 蚈画をコンパむルおよびデバッグしようずする堎合にのみ、いく぀かの問題が発生する可胜性がありたす。 事実、カヌネル空間では、glibcラむブラリの䜿い慣れた関数は䜿甚できず、カヌネルで提瀺された関数のみを䜿甚できたす。 さらに、むンタラクティブなコヌドのデバッグは非垞に困難です。


しかし、この堎合、キャラクタヌデバむス/dev/watchdogを実装するのはタスクが非垞に簡単なので、怖いこずはありたせん コヌドは完党に wrn_wdt.cです 。 デバむスはドラむバヌ番号10その他のデバむスによっおサヌビスされるため、最初に適切なデヌタ構造を決定する必芁がありたす。


 static struct miscdevice wrn_wdt_miscdev = { .minor = WATCHDOG_MINOR, //   watchdog .name = "watchdog", //    /dev .fops = &wrn_wdt_fops, //      }; 

次に、ハンドラヌを蚭定したす。


 static const struct file_operations wrn_wdt_fops = { .owner = THIS_MODULE, //     .llseek = no_llseek, //      .write = wrn_wdt_write, //      .unlocked_ioctl = wrn_wdt_ioctl, // ioctl .open = wrn_wdt_open, //     .release = wrn_wdt_release, //     }; 

ここで、unlocked_ioctl、これはioctlを介しおデバむス蚘述子にアクセスするための通垞のハンドラです。しばらくの間、呌び出しは非ブロッキングになりたした。したがっお、必芁に応じお同期するために远加の察策が必芁です


次に、モゞュヌルのロヌドおよびアンロヌド操䜜のハンドラヌを定矩する必芁がありたす。


 module_init(wrn_wdt_init); //       module_exit(wrn_wdt_exit); //     

必芁に応じお、module_param、MODULE_PARM_DESCを介しおモゞュヌルにパラメヌタヌを远加し、順序を指定できたす。


 MODULE_DESCRIPTION("..."); //  MODULE_AUTHOR("..."); //  MODULE_LICENSE("..."); //  

次のコマンドでこの情報を衚瀺できたす。


 modinfo [path]/[module].ko 

このステップで、ドラむバヌはほずんど準備ができおいたす。 これを行うには、少なくずもシリアルポヌトにデヌタを送信する機胜が必芁です。 これは、カヌネルスペヌスではAPIが提䟛されおいないため、盎接行うこずはできたせん。 暙準ドラむバヌの削陀ず独自のドラむバヌの開発に関連するオプションは、むデオロギヌ的に正しくないものずしおすぐに陀倖できたす。 したがっお、2぀のオプションが残りたす。


  1. カヌネルスペヌスから、ナヌザヌスペヌスのファむルシステムにアクセスしたす。
  2. LDISCカヌネルスペヌスに登録しおラむンディシプリン、シリアルポヌトトラフィックをむンタヌセプトおよび制埡したす。

最初のオプションを遞択したこずはすでに明らかであり、これに぀いお蚀い蚳はできたせん。 真剣に、回線制埡を䜿甚しお、トラフィックマネヌゞャをカヌネル空間に配眮する必芁がありたす。 ただし、既に述べたように、この空間でのプログラミングずデバッグは簡単な問題ではなく、可胜であれば、ナヌザヌ空間で実行できるI / O操䜜ず同様に、回避する必芁がありたす。


しかし、そのようなドラむバヌの䞍適切な開発の䞻な理由は、あたかもそれがUSBドラむバヌであるかのように独立性を達成するこずができないこずです。 ラむンディシプリンは、ポヌトパラメヌタを蚭定し、必芁なラむンディシプリンを蚭定するために、ナヌザヌ空間にコヌドを必芁ずする単なるレむダヌです。


可胜であれば、遞択が行われ、メむンドラむバヌコヌドは次のようになりたす。


 static int __init wrn_wdt_init(void) { int ret; //     ,     wrnd  filp_port = filp_open(serial_port, O_RDWR | O_NOCTTY | O_NDELAY, 0); if (IS_ERR(filp_port)) ... //   else { ret = misc_register(&wrn_wdt_miscdev); //  miscdevice if (ret == 0) wdt_timeout(); //     } return ret; } static void wdt_enable(void) { ... //   spin_lock(&wrn_wdt_lock); //  ( ) // watchdog   keep-alive      interval, //  WRN   ,    getnstimeofday(&t); time_delta = (t.tv_sec - wdt_keep_alive_sent.tv_sec) * 1000; // sec to ms time_delta += (t.tv_nsec - wdt_keep_alive_sent.tv_nsec) / 1000000; // ns to ms if (time_delta >= WDT_MIN_KEEP_ALIVE_INTERVAL) { //     cmd_keep_alive    fs = get_fs(); //    FS set_fs(get_ds()); //    KERNEL_DS (    ) ret = vfs_write(filp_port, cmd_keep_alive, strlen(cmd_keep_alive), &pos); set_fs(fs); //  FS if (ret != strlen(cmd_keep_alive)) ... //   getnstimeofday(&wdt_keep_alive_sent); } spin_unlock(&wrn_wdt_lock); //  ( ) } static long wrn_wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { ... //   switch (cmd) { case WDIOC_KEEPALIVE: wdt_enable(); ret = 0; break; case WDIOC_SETTIMEOUT: ret = get_user(t, (int *)arg); //      ... //    timeout = t; wdt_timeout(); wdt_enable(); /*   */ case WDIOC_GETTIMEOUT: ret = put_user(timeout, (int *)arg); //      break; ... //   } return ret; } 

䞊蚘のコヌドスニペット以倖では、MAGICCLO​​SEサポヌトが残りたす。 これは、デバむスファむルを閉じるずきにドラむバヌがりォッチドッグを無効にするために必芁です。 したがっお、システムによっおファむルが閉じられるwatchdogデヌモンの異垞なシャットダりンを認識するこずが重芁です。 この堎合、MAGICCLO​​SEメカニズムは再起動を保蚌するのに圹立ちたす。 そのサポヌトは、特殊文字通垞はVを受信した盎埌にデバむスファむルが閉じられた堎合にのみ、りォッチドッグタむマヌの非アクティブ化を提䟛したす。


ドラむバヌは、 make driverコマンドでMakefileを䜿甚しお構築され、その䞀郚は次のこずを行いたす。


 TARGET_WDT = wrn_wdt ifneq ($(KERNELRELEASE),) #  ,        obj-m := $(TARGET_WDT).o else #      make KERNEL := $(shell uname -r) #        driver: $(MAKE) -C /lib/modules/$(KERNEL)/build M=$(PWD) #         install: driver $(MAKE) -C /lib/modules/$(KERNEL)/build M=$(PWD) modules_install endif 

システムの起動時にむンストヌル埌にモゞュヌルをロヌドするには、次の行を/etc/conf.d/modulesファむルに远加する必芁がありたす。


 modules="wrn_wdt" 

手動モゞュヌルは、コマンドmodprobe wrn_wdtたたはinsmod ./wrn_wdt.ko modprobe wrn_wdt insmod ./wrn_wdt.koたす。 アップロヌド modprobe -r wrn_wdtたたはrmmod wrn_wdt ; モゞュヌルがロヌドされおいるこずを確認しおください lsmod | grep wrn_wdt lsmod | grep wrn_wdt 。


watchdogデヌモンのデバむスファむルずしおwdt.fifoチャネルを䜿甚する堎合、䟝存関係が正しく蚭定され、 wrndデヌモンがより早く起動し、埌でwatchdogを停止するこずを確認するこずが重芁です。 そうしないず、それに応じお、FIFOチャネルがただ䜜成されおいないか、タむマヌが非アクティブにならないため、䞍芁な再起動が発生する可胜性がありたす。



鬌


wrndデヌモンの目的は、シリアルポヌトからのバむナリデヌタのストリヌムを゜ヌトし、それらをサヌビスに䟿利な圢匏に倉換するこずです。


シリアルポヌト蚭定はデフォルトでテキスト端末向けに最適化されおいるため、それらをラむンに入れ、デバむスず動䜜モヌドを調敎する必芁がありたす 完党なコヌド serialport.c 


 //    termios       /  struct termios2 ttyopts; memset(&ttyopts, 0, sizeof ttyopts); //    if (ioctl(fd, TCGETS2, &ttyopts) != 0) ... //   //          ttyopts.c_cflag &= ~CBAUD; ttyopts.c_cflag |= BOTHER; ttyopts.c_ispeed = speed; // unsigned int,     B9600 ttyopts.c_ospeed = speed; ... //         //         ttyopts.c_cc[VMIN] = vmin; //  ( )        ttyopts.c_cc[VTIME] = vtime; //    if (ioctl(fd, TCSETS2, &ttyopts) != 0) ... //   

ここで最適なVMINおよびVTIME倀を遞択するこずが重芁です。 それらがれロである堎合、ポヌトはシステムリ゜ヌスを䞍必芁に消費する遅延なしでポヌリングされたす。 デヌタがない堎合、れロ以倖のVMIN倀は、フロヌを無制限にブロックできたす。


この堎合、デヌタはメむンプログラムストリヌムで1バむト読み蟌たれたす。 長時間ブロックするのは良くないので、VMINは垞にれロであり、VTIMEはパラメヌタヌで倉曎できたす。デフォルトでは5最倧遅延0.5秒です。


受信したバむトは、固定サむズのバッファに到着したす。 予想されるバむト数を受け取るず、バッファヌは察応するデヌタ構造構造に倉換されたす。 この方法は優れおいたすが、芚えおおく必芁がある機胜がありたす。 コンパむラは、フィヌルド間にスペヌスを远加し、通垞は単語の境界に合わせおフィヌルドを配眮するこずにより、デヌタ構造を最適化したす。 デヌタは異なるプラットフォヌム間で送信されるため、ワヌドサむズずバむト順゚ンディアンが異なるため、䞍敎合が発生する可胜性がありたす。


アラむメントを解消するには、デヌタ構造をパックずしお宣蚀する必芁がありたす。 AtmelStudioのプロゞェクトはデフォルトで-fpack-structスむッチを䜿甚しお-fpack-structれるため、このキヌのキャンセルに関する譊告がないこずを確認しおください。 デヌタアクセスの速床のためにメモリを節玄するタスクがないため、このキヌを䜿甚しおwrndプロゞェクトをアセンブルするこずはお勧めできたせん。 必芁に応じお、察応する属性を指定するだけで十分です。次に䟋を瀺したす。


 struct payload_header { ... //   } __attribute__ ((__packed__)); 

プロセスは、 daemon機胜によっおバックグラりンドで開始されdaemon 。


 if (arguments->daemonize && daemon(0, 0) < 0) ... //   

その結果、新しいPIDを持぀プロセスフォヌクのコピヌが䜜成され、それがさらに機胜し続け、珟圚のプロセスが終了したす。 関数の匕数は、新しいプロセスでは、ルヌトディレクトリを機胜するように蚭定し、暙準入力、出力、および゚ラヌストリヌムを/dev/nullリダむレクトする必芁があるこずを瀺しおい/dev/null 。


リヌダヌが接続されおいないFIFOに曞き蟌もうずしたずきにデヌモンがシャットダりンしないようにするには、SIGPIPEシグナルを無芖する必芁がありたす。


 signal(SIGPIPE, SIG_IGN); 

コヌドの残りの目的は、次のようにリストできたす。



チャンネルrng.fifo


デヌタは、玄636バむト/秒の速床でバむナリ圢匏でチャネルに盎接送信されたす。 ゚ントロピヌを/dev/randomに远加するには、 rngdデヌモンが䜿甚されたす。 必芁な゜ヌスのみを䜿甚するには、パラメヌタ " --no-tpm=1 --no-drng=1 --rng-device /run/wrnd/rng.fifo "を圌に枡す必芁がありたす。


ここで、゚ントロピヌの欠劂の問題を解決するために、真の乱数ゞェネレヌタヌを䜿甚する必芁がないこずに泚意する䟡倀がありたす。 パラメヌタヌ " --rng-device /dev/urandom "を指定しおrngdを実行するだけで十分です。 /dev/urandom䜿甚されるアルゎリズムは十分であり、そうしないこずを掚奚するこずは通垞完党に正圓化されおいたせん。 比范テストの結果は、出版物の終わり近くの最初の郚分で芋るこずができたす。


真に乱数を生成するこずを遞択したのは簡単です-同様のデバむスを組み立おたかったのですが、それに察する議論は芋぀かりたせんでした。


チャンネルnrf.fifo


センサヌからのデヌタは凊理され、SQLク゚リの圢匏でチャネルに送信され、テヌブルにレコヌドが挿入されたす。 wrnsensors.shの䟋は、SQLite3デヌタベヌスでの䜜業を瀺しおいたすが、INSERTク゚リは普遍的であり、どのSQLデヌタベヌスでも機胜するはずです。


チャンネルcmd.fifo


チャネルは、以䞋でwrnctrl管理wrnctrlによっお䜿甚されたす。


make daemonコマンドでMakefileを䜿甚しおwrndをwrndできmake daemon 。 デバッグバヌゞョンをビルドするためのデバッグタヌゲットが提䟛されたす。



管理ナヌティリティ


ナヌティリティwrnctrlはcmd.fifoチャネルからデバむスからデヌタを受け取るため、 wrndデヌモンをwrnctrlする必芁がwrndたす。


リヌダヌはすべおの゜ヌスからデヌタを受信したすが、FIFOを同時に開くず、予枬可胜な結果が埗られたすが、蚘録のみが可胜です。 耇数のリヌダヌが1぀のFIFOを開く堎合、どのリヌダヌがデヌタを受信するかを予枬するこずは䞍可胜です。 この動䜜は定矩䞊正しいですが、望たしくないため、cmd.fifoぞのアクセスを同期する必芁がありたす。


Linuxではflockを䜿甚しおファむルがビゞヌであるこずを宣蚀できるため、コヌド内でのみ同時にファむルを凊理するこずを陀倖できたす。 このメカニズムは名前付きパむプでは機胜しないため、 /tmp内の远加ファむルを䜿甚する必芁がありたす 完党なコヌド wrnctrl 。


 function device_cmd() { cmd=$1 #   #    (subshell),       4 ( #     4,      if ! flock -w ${FIFO_MAX_WAIT} 4; then return; fi #    #     ,    if [ -O ${LOCK_NAME} ]; then chmod 666 ${LOCK_NAME}; fi #  cmd.fifo   3,   exec 3< <(timeout ${FIFO_MAX_LOCK} cat ${WRND_CMDFIFO}) sleep 0.2 #       if [ -r /dev/fd/3 ]; then echo "$cmd" >${WRND_DEVICE} #      #  ,    FIFO   timeout while read log_line <&3; do echo "$log_line" #   done exec 3>&- #    3 fi ) 4>${LOCK_NAME} #  4      subshell,    } 

デバむスファヌムりェアの堎合、 wrnctrl flash [firmware].hexたす。 開始する前に、 watchdogおよびwrnd停止する必芁がありwrnd 。 このコマンドはavrdudeナヌティリティを䜿甚したす。たずえば、パッケヌゞマネヌゞャヌからむンストヌルできたす。


 emerge -av dev-embedded/avrdude 

䞊蚘のファむルに加えお、プロゞェクトむンストヌルパッケヌゞには次のものも含たれおいたす。



プロゞェクトの組み立おずむンストヌルは、 make installコマンドで行いたす。 むンストヌルは、スヌパヌナヌザヌ特暩rootで実行する必芁がありたす。 ファむルはシステムナヌティリティinstallによっおコピヌされたす。これにより、タヌゲットファむルの暩限ず所有者をすぐに蚭定できたす。


おわりに


このデバむス甚のUSBむンタヌフェヌスが確実に望たしいでしょう。 しかし、サヌバヌに䜿甚可胜なUSBポヌトがないため、この圢匏でプロゞェクトが衚瀺されたした。 それにもかかわらず、それはかなりシンプルで安定した䜜業デバむスであるこずが刀明したので、再生に匷くお勧めしたす。



Source: https://habr.com/ru/post/J300968/


All Articles