目的:
WEB画面から raspberry pi に 接続した LED の ON/OFF を行う。
php から Cプログラム へ メッセージキュー を使用したプロセス間通信を使用する。
環境/構成:
環境/構成は、
WEB から LED ON/OFF
と同じ。
プロセス間通信:
プロセス間通信にはいろいろな種類があるが、ここではメッセージキューを使用した通信を行い、php から Cプログラムに LED ON/OFF の指示を行う。
php から のメッセージ送信
php からメッセージを送信するには、
- msg_get_queue (int $key , int $permissions)
で、指定された key でメッセージキューの作成または接続を行い、IDを取得する。
prtmissions : 0666 (default 値) 。 - msg_send(SysvMessageQueue $queue , int $message_type ,
string|int|float|bool $message , bool $serialize )
で、メッセージの送信を行う。
queue : 1. で取得した ID
message_type : メッセージのタイプ (0 より大きな任意の数値)
message : 送信するメッセージの本体
serialize : ここでは FALSE を指定。(default は TRUE)
c プログラムでのメッセージ受信
- msgget(key_t key, int msgflg);
で、指定された key で メッセージキューの作成または接続を行い、IDを取得する。
msgflg : 下位9bit は permission。作成を行う場合は IPC_CREAT を指定する。 - msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
で、メッセージの受信を行う。
msgid : 1. で取得した ID
msgp : メッセージの構造体へのポインタ
msgsz : メッセージ構造体の中の データの最大バイト数
msgtyp : メッセージのタイプ。0 を指定した場合は キューの最初のメッセージが読み込まれる。
msgflg : メッセージフラグ。IPC_NOWAIT を指定した場合、キューにメッセイー時が無い場合に直ちに帰る。(errno には ENOMSG が設定)
phpファイル:
ここでは、key に "1111" を指定する。後述の Cプログラムの key と同じにする。
"ON", "OFF" の ボタンが押下された時、led_on, led_off の文字列をメッセージ送信する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <?php $QKEY = 1111; $QUEUE = msg_get_queue( $QKEY , 0666); if ( $_GET [ 'on' ] == "ON" ) msg_send( $QUEUE , "1111" , "led_on\0" , FALSE) ; if ( $_GET [ 'off' ] == "OFF" ) msg_send( $QUEUE , "1111" , "led_off\0" , FALSE) ; ?> <!DOCTYPE html><html lang= 'ja' > <head><meta charset= 'UTF-8' > <style> input {margin:8px;width:100px;} div {font-size:16pt;text-align:center;width:250px;border:solid 4px #93ff93;} </style> <title> Color LED Controller </title> </head> <body> <div> <p>LED CONTROL</p> <form method= 'get' > <input type= 'submit' name= 'on' value= 'ON' /> <input type= 'submit' name= 'off' value= 'OFF' /> </form> </div> </body> </html> |
Cプログラム:
Cプログラムでは、php からの メッセージを受信し、メッセージに応じて LED の 点灯/消灯を行う。
メッセージキューの key は php と 同じ "1111" を使用する。
メッセージ受信時の msgtyp (read_type) は '0' を指定し、メッセージタイプに関わらず、先頭から受信する。
while 文で メッセージ受信をループ処理するが、同時にキーボードを監視し、"exit(rtn)"をタイプしたらプログラムを終了するようにする。キーボード入力を メッセージ受信と並行して行うためにキーイベントの取得(kbhit) を行うが、このコードは こちらのコードを使用させて頂いた。
その他説明等、コード中のコメントを参照のこと。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | #include <wiringPi.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <termios.h> #include <fcntl.h> // ***************************************************************************** // * 定義等 * // ***************************************************************************** // メッセージキュー 用 定義 ---------------------------------------------------- #define BUFFSIZE 256 // バッファサイズ #define QKEY (key_t)1111 // メッセージキューの key // struct msgbuf{ // メッセージの構造体 long int type; // type は long int であること。 char data[BUFFSIZE]; // }; // // // LED ON/OFF 用 定義 ---------------------------------------------------------- #define led_pin 12 // LED を接続する GPIO # // // ***************************************************************************** // * キーイベントの取得 * // ***************************************************************************** // int kbhit( void ) { // struct termios oldt, newt; // int ch; // int oldf; // // tcgetattr(STDIN_FILENO, &oldt); // newt = oldt; // newt.c_lflag &= ~(ICANON | ECHO); // tcsetattr(STDIN_FILENO, TCSANOW, &newt); // oldf = fcntl(STDIN_FILENO, F_GETFL, 0); // fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); // // ch = getchar (); // // tcsetattr(STDIN_FILENO, TCSANOW, &oldt); // fcntl(STDIN_FILENO, F_SETFL, oldf); // // if (ch != EOF) { // ungetc (ch, stdin); // return 1; // } // // return 0; // } // // // ***************************************************************************** // * メイン 関数 * // ***************************************************************************** int main() { // int msqid; // メッセージキュー ID struct msgbuf message; // メッセージ long int read_type = 0 ; // リードするメッセージタイプ char c ; // 1文字入力用 char buf[128] ; // キーボード入力用のバッファ int p_buf = 0 ; // 入力位置 // // メッセージキューの作成,取得 ----------------------------------------------- // 誰でも読み書き可能なキューを作成して、ID を取得する -- errno = 0; // if ( ( // msqid = msgget(QKEY, 0666 | IPC_CREAT) // 0666:アクセス許可パラメータ ) == -1 ) { // perror ( "msgget failure" ); // 作成失敗時の処理 exit (EXIT_FAILURE); // } // // // wiringpi の設定 ----------------------------------------------------------- wiringPiSetupGpio() ; // pinMode (led_pin, OUTPUT) ; // // // メッセージを受信して LED の ON/OFF を行う --------------------------------- while (1){ errno = 0 ; // if (!(msgrcv( msqid, &message, BUFFSIZE, // メッセージの受信 read_type, IPC_NOWAIT) == -1) // ) // { // メッセージ受信時の処理 fprintf (stdout, "received message:\t%s\n" ,message.data); if ( strcmp (message.data, "led_on" ) == 0) { // digitalWrite (led_pin, HIGH) ; // LED 点灯 } // if ( strcmp (message.data, "led_off" ) == 0) { // digitalWrite (led_pin, LOW) ; // LED 消灯 } // } else { // 受信失敗時 if ( errno != ENOMSG) { // メッセージ無し以外は終了 printf ( "msgrcv : errno = %x\n" , errno ) ; // break ; // } // } // // キーイベントを取得し、入力文字列が "exit" ならループを終了する。---------- if (kbhit()) { // c = getchar () ; // 入力された文字を表示 printf ( "%c" ,c) ; // if ( c == '\n' ) { // リターン入力時 if ( strcmp (buf, "exit" ) == 0 ) { // "exit" を入力ならループ終了 break ; // } else { // "exit" でなければ、先頭に戻る p_buf = 0 ; // buf[p_buf] = '\0' ; // } // } else { // リターンでなければ、 if (p_buf == 255) p_buf = 0 ; // バッファサイズを超える時は先頭へ buf[p_buf] = c ; // バッファに入力文字を追加 buf[p_buf + 1] = '\0' ; // p_buf++ ; // 入力位置を +1 } // } // } // // // メッセージキューを削除して終了 ---------------------------------------------- errno = 0; // if (msgctl(msqid, IPC_RMID, NULL) == -1){ // perror ( "msgctl failure" ); // exit (EXIT_FAILURE); // } // // exit (EXIT_SUCCESS); // // } // // // |
コンパイルは、
gcc -o ledctl ledctl.c -lwiringPi
実行:
raspberry pi で ledctl を実行
./ledctl
し、ブラウザから、
http://"raspberry pi の アドレス"/"html のディレクトリ"/led_ctl.php
にアクセスする。(led_ctl.php は 上で格納した php ファイル)
以下の様な画面が表示される。
ON ボタン押下 で LED ON,
OFF ボタン押下で LED OFF
Cプログラムの終了は、"exit(rtn)" の入力で終了する。
尚、ctrl-C で終了した場合等、メッセージキューが残ったままになる。
コマンドラインがら、
ipcs
で メッセージキュー の状態が確認できる。
メッセージキューの削除は、
sudo ipcrm -q [msqid]
で行う。
( msqid は、ipcs コマンド で 確認できる )
0 件のコメント:
コメントを投稿