2020年12月9日水曜日

raspberry pi : WEB から LED 調光 ( php - C言語 間通信 )

 目的:

WEB画面から raspberry pi に 接続した LED の PWM制御による 調光 を行う。
php から Cプログラム へ メッセージキュー を使用したプロセス間通信を使用する。

環境/構成:

環境/構成は、 WEB から  LED ON/OFF と同じ。 
プロセス間通信については、WEB から  LED ON/OFF ( php - C言語 間通信 ) を参照。
PWM制御については、C言語で LED 調光 (PWM 制御) を参照。

phpファイル(WEB画面):

WEB画面は、ESP32/arduino:LED調光_スライダーで明るさを調整 と同じ画面。


以下に、phpファイル (HTML) を示す。

php(html)本体 (led_pwm.php)
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
<?php
  $QKEY = 1111;
  $QUEUE = msg_get_queue($QKEY, 0666);
 
  session_start() ;
  if ($_SESSION['led_val'] == NULL ) $_SESSION['led_val'] = 0 ;
  
  if ($_GET['led_v'] != NULL) {
    $_SESSION['led_val'] = $_GET['led_v'] ;
    msg_send($QUEUE, "1111", "set_ledval " . $_SESSION['led_val'] . "\0" , FALSE) ;
    }
 
  if ($_GET['led_s'] != NULL) {
    $_SESSION['led_val'] = $_GET['led_v'] ;
    msg_send($QUEUE, "1111", "set_ledval " . $_SESSION['led_val'] . "\0" , FALSE) ;
    }
 
  if ($_GET['on'] == "ON") {
    $_SESSION['led_val'] = "255" ;
    msg_send($QUEUE, "1111", "led_on\0" , FALSE) ;
    }
   
  if ($_GET['off'] == "OFF") {
    $_SESSION['led_val'] = "0" ;
    msg_send($QUEUE, "1111", "led_off\0" , FALSE) ;
    }
 
  $led_brightness = $_SESSION['led_val'] ;
?>
 
<!DOCTYPE html><html lang='ja'><head><meta charset='UTF-8'>
<style>input.button  {margin:8px;width:100px;}
       input.button2 {margin-left:8px; width:40px;}
       input.text    {margin-left:8px; width:25px;}
       input.slid    {width:230px;}
       div   {font-size:16pt;text-align:center;width:250px;border:solid 4px #93ff93;}
       </style>
<title>Color LED Controller</title></head>
 
<body>
<div><p>LED ON/OFF</p>
  <form method='get' style='text-align:left' >
    <span style='padding-left:15pt; font-size:8pt ;text-align:left'> LED brightness (0-255)</span>
    <input class='text'  type='text' name='led_v' id='led_v' value=<?=$led_brightness?> >
    <input class='button2' type='submit' name='set' value='SET'>
  </form>
 
  <form name='slidform' method='get' style='text-align:left'>
    <input class='slid' type='range' name='led_s' value=<?=$led_brightness?> min='0' max='255' step='1' onchange='setval(this.value)' oninput='setval(this.value)' >
  </form>
 
  <form method='get'>
    <input class='button' type='submit' name='on' value='ON'><input class='button' type='submit' name='off' value='OFF'><br>
  </form>
 
  </div>
 
 
<script>
function setval(ledval){
  var xhr = new XMLHttpRequest();
  xhr.open('get', 'pwm_resp.php?slid='+ledval );
  xhr.timeout = 1000 ;
  xhr.setRequestHeader('Cache-Control', 'no-cache');
  xhr.setRequestHeader('If-Modified-Since', 'Thu, 01 Jun 1970 00:00:00 GMT');
  xhr.responseType = 'document' ;
 
  xhr.onreadystatechange = function() {
      if( (xhr.readyState == 4) && (xhr.status == 200) ) {
          document.getElementById('led_v').value = xhr.response.getElementById('output1').innerHTML;
      }
  }
  xhr.ontimeout = function(e) {
      xhr.abort() ;
  }
  xhr.send();
}
 
</script>
</body>
</html>

XHR レスポンス用 (pwm_resp.php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
  $led_brightness = $_GET['slid'] ;
  $QKEY = 1111;
  $QUEUE = msg_get_queue($QKEY, 0666);
 
  msg_send($QUEUE, "1111", "set_slidval " . $led_brightness . "\0" , FALSE) ;
?>
 
<!DOCTYPE html><html lang='ja'>
  <head> <title>Color LED Controller</title></head>
  <body>
 
  <output id='output1'> <?=$led_brightness?> </output>
 
  </body> </html>

処理の流れ:

  • php 本体では、各 GET 要求を受けたとき、メッセージキューに LED 操作のコマンドを送信する。また、HTML 中の変数($led_brightness) に値を設定する。
  • HTML中の変数($led_brightness) は、php のショートタグ( <?=*** ?> ) を使用して値に置き換える。
  • スライダー操作時は、javascript で XHRを使用して 値を XHRレスポンス用 php に送信する。
  • XHR レスポンス用 php では、送信された値を受け、メッセージキューに LED 操作のコマンドを送信し、受信した値をそのままレスポンスとして返す。ここでは、HTML(テキスト) でレスポンスを返している。

各処理の内容については、上述の参照ページを参照。

Cプログラム(LED調光):

Cプログラムは、 WEB から  LED ON/OFF ( php - C言語 間通信 ) の LED ON, OFF を PWM制御 ( C言語で LED 調光 (PWM 制御) ) に置き換えたものとなる。
プログラムを以下に示す。
LED調光 (ledctl.c)
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#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 ;                               // 入力位置
  char *cmd ;                                    // コマンド用バッファ
  char *prm1 ;                                   // パラメータ1用バッファ
  int  val = 0 ;                                 // 設定値
                                                 //
  // メッセージキューの作成,取得 -----------------------------------------------
  //   誰でも読み書き可能なキューを作成して、ID を取得する                    --
  errno = 0;                                     //
  if( (                                          //
        msqid = msgget(QKEY, 0666 | IPC_CREAT)   // 0666:アクセス許可パラメータ
      ) == -1 ) {                                //
    perror("msgget failure");                    //   作成失敗時の処理
    exit(EXIT_FAILURE);                          //
  }                                              //
                                                 //
  // wiringpi の設定 -----------------------------------------------------------
  wiringPiSetupGpio() ;                          //
  pinMode (led_pin, PWM_OUTPUT) ;                //   LED 調光
  pwmSetMode(PWM_MODE_MS) ;                      // PWM モード設定
  pwmSetClock(40) ;                              // PWM 分周比設定(レンジ当たりのクロック数)
  pwmSetRange(255) ;                             // PWM 分解能設定(1周期当たりのレンジ数)
                                                 //
  // メッセージを受信して LED の ON/OFF を行う ---------------------------------
  while(1){
    errno = 0 ;                                  //
    if (!(msgrcv( msqid, &message, BUFFSIZE,     // メッセージの受信
                 read_type, IPC_NOWAIT) == -1)   //
        )                                        //
    {                                            // メッセージ受信時の処理
      // メッセージをコマンドとパラメータに分割 -//
      cmd = strtok(message.data, " ") ;          // 最初の文字列(" "まで) をコマンド
      prm1 = strtok(NULL, " ") ;                 // 次の文字列を パラメータ1
      printf("command : %s %s\n",cmd,prm1);      // 表示
                                                 //
      if (strcmp(cmd,"led_on") == 0) {           //    LED ON
        pwmWrite(led_pin, 256) ;                 //    LED 調光値設定(ON : 256)
      }                                          //
      if (strcmp(cmd,"led_off") == 0) {          //    LED OFF
        pwmWrite(led_pin, 0  ) ;                 //    LED 調光値設定(OFF : 0)
      }                                          //
      if (strcmp(cmd,"set_ledval") == 0) {       //    LED 調光値設定
        val = atoi (prm1) ;                      //    パラメータ1 を数値に変換
        pwmWrite(led_pin, val) ;                 //    LED 調光値設定
      }                                          //
      if (strcmp(cmd,"set_slidval") == 0) {      //    LED スライダー値設定
        val = atoi (prm1) ;                      //    パラメータ1 を数値に変換
        pwmWrite(led_pin, val) ;                 //    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);                            //
                                                 //
}                                                //
                                                 //
                                                 //

メッセージキューに送信されたコマンドに従い、LED の値 を設定する。
本プログラムを sudo 付きで実行し、WEB から 上述のphp(html) を開いて 操作すると、スライダーに応じて LED の明るさが変わる。
端末から "exit(rtn)" を入力すると プログラムは停止する。

0 件のコメント:

コメントを投稿