目的:
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 の文字列をメッセージ送信する。
<?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) を行うが、このコードは こちらのコードを使用させて頂いた。
その他説明等、コード中のコメントを参照のこと。
#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 件のコメント:
コメントを投稿