ラベル raspberry pi の投稿を表示しています。 すべての投稿を表示
ラベル raspberry pi の投稿を表示しています。 すべての投稿を表示

2025年2月12日水曜日

raspberry pi : OS インストール(Raspberry Pi Imager, SSH, 無線LAN)

目的:

ラズベリーパイ に Raspberry Pi Imager を使用して Raspberry Pi OS をインストールする。
ラズベリーパイ 用には モニタ、キーボード、マウス、有線LAN は接続せず、 Windows PC から無線LANで SSH接続して行う。

手順:

Raspberry pi の モニタ、キーボード、マウス、有線LAN は 接続しない前提での インストール手順。
LAN は 無線LAN。
今回は、raspberry pi 5 に、64bit版 をインストール。

(1) imager のダウンロード

https://www.raspberrypi.com/software/(raspberry pi 公式 softwear ページ )
から 「Download for Windows」を押下して ダウンロードする。

(2) imager のインストール

ダウンロードした imager_*.*.*.exe  を 実行し、インストールを行う。
(今回は imager_1.8.5.exe)
インストール終了時「Run Raspberry Pi Imager」にチェックマークがついた状態で「Finish」を押下することで、SDカードへの OS書き込みを開始する。

(3) SDカードへの OS書き込み

Raspberry Pi Imager を実行し、各項目の設定を行う。
  • Raspberry Piデバイス
    Raspberry Pi の種類を選択する。(今回は Raspberry pi 5)
  • OS
    OS の種類を選択する。(今回は Raspberry pi OS (64-bit)
  • ストレージ
    書き込み用の MicroSDカードを挿入し、書き込み先を選択する。
設定すると、「次へ」のボタンが押下できるようになる為、押下する。
カスタマイズするかを聞かれる為、「設定を編集する」を押下する。
設定画面となる為、各項目の設定を行う。
  • 「一般」タブ
    ホスト名, ユーザ名, パスワード, WiFi設定, ロケール のチェック, 設定を行う。

  • 「サービス」タブ
    SSHを有効化する にチェックを入れる。
を設定し 「保存」 を押下し、「はい」を押下
ストレージに保存されているデータが削除されることの確認に対して 「はい」を押下すると、MicroSD への 書き込みが開始される。

(4) Power ON 

Raspberry Pi に MicroSDカードを挿入して電源を接続し、電源onする。

(5) SSH でLOGIN

raspberry pi に SSH で LOGIN する。
IPアドレスは DHCP で割り当てられた IP アドレスで 立ち上がるため、IPアドレスは推定で指定する。
 NetEnum 等で ネットワーク上に存在する IPアドレス (ping の通ったアドレス)  を調べ、アタリをつける。
SSH 接続時の ID,  パスワード は 設定した値を使用。
SSH 接続は、Windows 上 の端末から、
ssh IPアドレス
で行う。

(6) 初期設定

SSH で接続できたら、以下の設定を行う。
  • root の パスワードを設定
    sudo passwd root
    で、root の パスワードを 設定する。
  • パッケージの更新
    sudo apt update
    で、パッケージ管理ツールをアップデートする。
     (パッケージリストの更新)
    sudo apt upgrade
    で、アップグレードをする。(インストールされてるパッケージの更新)
  • ロケール設定 (日本語対応)
    sudo raspi-config
    で 以下のようにロケールの設定を行う。
    5 Localisation Options を選択して Return。
    L1 Locale  を選択して Return。
    en_GB.UTF-8 UTF8 でスペースキーを押下して '*' を外す。
    ja_JP.UTF-8 UTF-8 で スペースキーを押下して '*' を付け、Return。
    次画面で
    ja_JP.UTF-8 を選択して Return。
    設定が終わったら、再起動を行う。
    sudo reboot
  • IPアドレスの固定
    設定ファイルは /etc/NetworkManager/system-connections にある。
    ファウル名は preconfigured.nmconnection
    このファイルの [ipv4] セクションを変更する。
    sudo vi /etc/NetworkManager/system-connections/preconfigured.nmconnection
    変更前
    [ipv4]
    method=auto
    変更後例
    [ipv4]
    method=manual
    addresses=192.168.1.94/24  // IPアドレス
    gateway=192.168.1.1        // ルータのIPアドレス
    dns=8.8.8.8;8.8.4.4;       // DNS の IPアドレス
    
        ファイルを変更したら、設定を反映させるため、再起動する。
    sudo reboot
    設定を反映させるため、NetworkManagerの再起動 する。
    sudo systemctl restart NetworkManager
    SSH 接続たと端末が固まってしまう。raspberry pi の 再起動でも良い。
    sudo reboot
    再起動後、設定した アドレスで 接続する。

2024年3月3日日曜日

raspberry pi : 固定IPアドレスにする (dhcpcd.conf が無い場合)

目的:

nmcli を使用して 固定IPアドレス を設定する。

背景:

Raspberry pi 5 で 固定IPアドレスを設定しようとしたところ、 /etc/dhcpcd.conf が存在しなかった。
OS の バージョンが bookworm になって 設定方法が変わった模様。

手順:

NetworkManager (nmcli) を使用して設定を行う。
設定は
  1. コマンドで設定する。
  2. 設定ファイルを編集して設定する。

のどちらでも可能。
nmcli の コマンド は コマンドが補完できるまで短縮可能 
例 : nmcli connection show   →   nmcli c s

1.コマンドで設定。

  1. 接続名の確認
    nmcli connection show
    で 接続名を確認
    NAME           UUID                                  TYPE      DEVICE 
    有線接続 1     xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx  ethernet  eth0   
    preconfigured  xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx  wifi      wlan0  
    lo             xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx  loopback  lo
    
    以降、設定等で 接続名(NAME)を使用するが、接続名 が日本語(2バイトコード) や スペース が含まれている場合は " (ダブルコーテーション) で括って使用する。
    但し、認識できない等の不具合を発生する場合も在りうるため、1バイトコードに変更した方が良い。(手順は こちら )

  2. IPv4 IPアドレス等を設定する
    IPアドレス
    sudo nmcli connection modify [接続名] ipv4.addresses "xxx.xxx.xxx.xxx/24"
    デフォルトゲートウェイ
    sudo nmcli connection modify [接続名] ipv4.gateway "xxx.xxx.xxx.xxx"
    DNS
    sudo nmcli connection modify [接続名] ipv4.dns "xxx.xxx.xxx.xxx"
    (DNS の IPアドレスは スペースで区切って 複数指定可能 )

  3. IPアドレス を 手動設定に変更する。
    sudo nmcli connect modify [接続名]  ipv4.method manual
    この設定は、IPアドレスの設定を行った後に行わないとエラーとなる。

  4. 反映
    sudo nmcli con up eth0

2. 設定ファイルを編集して設定。

設定ファイルは 以下となる。(接続名毎に設定ファイルがある)
/etc/NetworkManager/system-connections/[接続名].nmconnection
  1. 接続名の確認
    nmcli connection show
    で 接続名を確認

  2. 設定ファイルを編集 設定ファイルの IPv4 の部分を書き換える。(br />
    hidden=false
    [ipv4]
    method=auto
    [ipv6]
    hidden=false
    [ipv4]
    address1=[IPアドレス]/24,[ゲートウェイアドレス]
    dns=[DNSアドレス1;DNSアドレス2];
    method=manual

    [ipv6]

  3. 反映
    sudo nmcli connection reload
    sudo nmcli con up preconfigured

* 接続名を変更する

接続名の変更は、古い接続名を削除して新しい接続名を追加することで行う。
接続名が日本語(2バイトコード) の場合、1バイトコードに変える。

  1. 接続名が日本語の接続を切断する
    sudo nmcli connection delete [UUID]
  2. 新しい接続名で接続を追加する
    sudo nmcli connection add type ethernet ifname [デバイス名] con-name [接続名]


2023年11月19日日曜日

raspberry pi : FANをPWM制御する (C言語)

目的:

ラズベリーパイのFAN (PWM制御対応のFAN> を PWM 制御 する。

背景:

ラズベリーパイのケースについているFAN から音が出るようになった。
(5V ファン を 3.3V 駆動 )
この為、PWM制御対応の5V FAN を購入し、説明書通り、/boot/config.txt に
dtoverlay=gpio-fan,gpiopin=18,temp=55000
を追加したところ、 指定温度 (55℃) 以上 で ON, 未満で OFF となり、FAN が 定期的に 全力回転 していた。(PWM制御ではなく、 ON/OFF 制御 )
この為、PWM制御 (回転数制御) できるようにする。

概要

PWM制御については、「C言語で LED 調光 (pigpio を使用した PWM 制御) 」を参照。
pigpiod(デーモン)を使用した hardware_PWM (ユーザ権限で実行可能) を使用し、指定温度範囲で 段階的に FAN回転数 を変える様にする。
尚、コード作成は C言語 で行う。

構成

raspberry pi : raspberry pi 4
FAN : PWM制御端子付き の 5V FAN
使用 GPIO : 18 pin


PWM FAN 制御用コード

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pigpiod_if2.h>

int get_temp(void) {
  static int tmp = 0;
  FILE *fp;
  char rdt[16];

  fp = fopen("/sys/devices/virtual/thermal/thermal_zone0/temp","r") ;
  if (fp != NULL ) {
    fgets(rdt,16,fp) ;
    fclose(fp);
    tmp = atoi(rdt) / 1000 ;
  }

  return tmp ;
}

void usage(void)
{
  printf("Usage: pigpio_pwnfan [option]\n");
  printf("\n");
  printf("  option\n (default)") ;
  printf("    -l n ... Low temperature (50)    'C\n");
  printf("    -h n ... hi  temperature (60)    'C\n");
  printf("    -p n ... PWM output pin  (18)    12/18(ch0) or 13/19(ch1)\n");
  printf("    -f n ... PWM Frequency   (10000) Hz\n");
  printf("\n");
}

int main(int argc, char **argv) {
  int gpio_pin = 18;      // hardware PWM Pin
  int pwm_freq = 10000;   // hardware PWM frequency
  int pwm_duty = 0 ;      // hardware PWM duty
  int tmp_low  = 50;      // cold temperature
  int tmp_hi   = 60;      // hot temperature
  int temp     = 0 ;      // detect twmperature
  int pi       = 0 ;
  int opt      = 0 ;

  // command line option 
  while ((opt = getopt(argc, argv, "l:h:p:f:")) != -1) {
    switch (opt) {
      case 'l':
        tmp_low = atoi(optarg);
        break;
      case 'h':
        tmp_hi  = atoi(optarg);
        break;
      case 'p':
        switch((gpio_pin = atoi(optarg))) {
          case 12:
          case 13:
          case 18:
          case 19:
            break;
          default:
            usage();
            exit(1);
        }
        break;
      case 'f':
        pwm_freq = atoi(optarg);
        break;
      default:
        printf("\n");
        usage();
        exit(1);
    }
  }

  if (tmp_low >= tmp_hi)
  {
    usage();
    exit(1);
  }


  // pigpio start
  pi = pigpio_start(0,0) ;
  if (pi<0) {
    printf ("pigpio start error !!") ;
    exit(1) ;
  }

  // PWM control
  while (1)
  {
    temp = get_temp();
    if (temp <= tmp_low) {
      pwm_duty = 0;
    } else if(temp >= tmp_hi) {
      pwm_duty = 1000000 ;       // 100%
    }else {
      pwm_duty = ((temp - tmp_low) * 1000000) / (tmp_hi - tmp_low) ;
    }

    hardware_PWM(pi,gpio_pin, pwm_freq, pwm_duty) ;

    sleep(10);
  }


  return 0;
}

コード概要

  1. get_temp(void)
    raspberry pi のCPU温度を取得する。
    温度の取得は /sys/devices/virtual/thermal/thermal_zone0/temp を読み込む事で行う。
  2. usage(void)
    オプション不正時の書式の表示を行う。
  3. main(int argc,char **argv) PWM FAN 制御 本体。
    1. command line option 解析部分 getopt を して オプションの解析を行う。
      unistd.h をインクルードする必要がある。
      -l : 下限温度。この温度より下は FAN停止。(省力時 50℃) -h : 上限温度。この温度より上は FAN全速。(省略時 60℃) -p : GPIO PIN番号。12/18(ch0) 又は 13/19(ch1) (省略時 18) -f : PWM 周波数 (省略時 10000 (10KHz) )
  4. pigpio start pigpio_start(0,9) (pigpio の 初期化) を実行。 戻り値が負の場合、異常終了。
  5. PWM control PWM 制御 本体。 設定温度の間、検出温度の応じてデューティを 0~100% の間で変化させる。 無限ループで、 温度の取得, PWM 設定 を行った後、10秒間 スリープする。 ( 10秒間隔で PWM制御 )

コンパイル

gcc -Wall -pthread -o pigpio_pwmfan pigpio_pwmfan.c -lpigpiod_if2 -lrt

実行

pigpiod 開始

sudo systemctl enable pigpiod.service
sudo systemctl start pigpiod.service

実行 (動作確認)

pigpio_pwmfan&
で実行し、FAN がPWM制御されていること(全速でないこと)を確認する。

停止

作成した FAN制御プログラムは サービスとして実行するため、動作確認で実行したプロセスを以下で終了させる。
ps
で pigpio_pwmfan の PIDを確認し、
kill [PID]
で pigpio_pwmfan を終了させる。

サービスへの登録

再起動時等、自動で開始するようにサービスに登録する。

ユニット定義ファイルの作成

/etc/systemd/system に ユニット定義ファイルを作成する。

ユニット定義ファイル例
[Unit]
# サービスの説明。内容は任意
Description=PWM FAN Control
# このUnitより先に起動するべきUnitを設定
After=local-fs.target
  
[Service]
# 実行するコマンドやスクリプトを記述
ExecStart=/usr/local/bin/pigpio_pwmfan
# サービス停止時の Kill する単位を設定
KillMode=process
# プロセスの起動方法を指定
Type=simple
# サービス停止時の再起動条件 (no は再起動しない)
Restart=always
 
[Install]
# 該当ユニットへの弱い依存関係を設定
WantedBy=multi-user.target

FAN制御プログラムの サービス登録、実行

sudo systemctl enable pigpiod.service
sudo systemctl start pigpiod.service






2023年11月6日月曜日

raspberry pi : C言語で LED 調光 (pigpio を使用した PWM 制御)

目的:

WiringPi は 非推奨になったとのことの為、pigpio を使用して PWM 制御を 行う。

概要:

pigpio による ハードウェアPWM を使用する場合、以下の2種類がある。
  1. gpioHardwarePWM を使用
    この場合、
    1. pigpiod (デーモン) を使用しない。( 動作していてはいけない )
    2. 実行は sudo を付けて行う必要がある。(管理者権限が必要)
  2. hardware_PWM を使用
    この場合、
    1. 実行 は sudo を 付けて実行する必要がある。
    2. 管理者権限は不要。
以下、この2種類について、記す。
( 参考 : The pigpio library : https://abyz.me.uk/rpi/pigpio/ )

gpioHardwarePWM による PWN 制御:

書式

gpioHardwarePWM(gpio番号, PWM周波数, PWMデューティ)
PWM周波数は 0 ~ 125000000  ( 0 ~ 125MHz)
PWMデューティ は 0 ~ 1000000 ( 0 ~ 100% )

注意事項等

インクルードファイル : pigpio.h
最初に、初期化 として gpioInitialise() を実行する必要がある。

サンプルコード

#include <pigpio.h>

#define GPIO_PWM1 18
#define GPIO_PWM2 19

#define PMW_FREQ    10000

int main(void)
{
    int ret = gpioInitialise();
    if (ret < 0)
    {
        return ret;
    }
    else
    {
        gpioHardwarePWM(GPIO_PWM1, PMW_FREQ, 100000);
        gpioHardwarePWM(GPIO_PWM2, PMW_FREQ, 700000);

        gpioSleep(PI_TIME_RELATIVE,5,0) ;

        gpioHardwarePWM(GPIO_PWM1, PMW_FREQ, 700000);
        gpioHardwarePWM(GPIO_PWM2, PMW_FREQ, 100000);

        gpioSleep(PI_TIME_RELATIVE,5,0) ;

        gpioHardwarePWM(GPIO_PWM1, PMW_FREQ, 0);
        gpioHardwarePWM(GPIO_PWM2, PMW_FREQ, 0);

        gpioTerminate();
    }

    return ret;
}

コンパイル

gcc -Wall -pthread -o pigpio_pwm pigpio_pwm.c -lpigpio -lrt
pigpio.h をインクルードしているため、 -lpigpio が必要。

実行

sudo ./pigpio_pwm
で gpio 18, 19 に PWMのパルス信号が 出力される。
サンプルコードでは 最初に出力した 5秒後に Duty を変えて出力。
その 5秒後に 出力を 停止する。

その他

pigpio を使用する場合は、管理者権限で実行する必要がある。( sudo で実行等)
pigpiod のデーモンは不要。( pigpiod が 動いていると実行できない )
通常の gpio へのアクセスは gpioWrite, gpioRead を使用する。

hardware_PWM による PWN 制御

pigpiod の注意事項

hardware_PWM を使用するには pigpiod を走らせる必要があるが、
pigpiod を走らせると、CPU のパワーを消費してしまう。
これは、ソフトウェア PWN の為 とのこと。
ソフトウェア PWM を使用しないのであれば、サンプリング機能を無効にする
オプション(-m) を付加することで、CPU の消費が少なくなる。

サンプリング機能を無効にする方法 ( CPUの使用率を下げる為)

設定は、 /lib/systemd/system/pigpiod.service を編集して行う。
pigpiod.service :
1 [Unit]
2 Description=Daemon required to control GPIO pins via pigpio
3 [Service]
4 ExecStart=/usr/bin/pigpiod -l -m
5 ExecStop=/bin/systemctl kill pigpiod
6 Type=forking
7 [Install]
8 WantedBy=multi-user.target
上記の通り、 ExecStart の ところに -m を追加する。

pigpiod 開始

pigpiod (デーモン) の開始は、
sudo systemctl enable pigpiod.service
sudo systemctl start pigpiod.service
で行う。
尚、pigpiod の停止は、
sudo systemctl disable pigpiod.service
sudo systemctl stop pigpiod.service
で行う。

書式

hardware_PWM(pi, gpio番号, PWM周波数, PWMデューティ)
pi は pigpio_start の戻り値
PWM周波数は 0 ~ 125000000  ( 0 ~ 125MHz)
PWMデューティ は 0 ~ 1000000 ( 0 ~ 100% )

注意事項等

インクルードファイル : pigpiod_if2.h
最初に、初期化 として pigpio_start(0,0) を実行する必要がある。

サンプルコード

#include <pigpiod_if2.h>

#define GPIO_PWM1 18
#define GPIO_PWM2 19

#define PMW_FREQ    10000

int main(void)
{
    int pi = pigpio_start(0,0) ;
    if (pi < 0)
    {
        return pi;
    }
    else
    {
        hardware_PWM(pi,GPIO_PWM1, PMW_FREQ, 100000);
        hardware_PWM(pi,GPIO_PWM2, PMW_FREQ, 700000);

        time_sleep(5) ;

        hardware_PWM(pi,GPIO_PWM1, PMW_FREQ, 700000);
        hardware_PWM(pi,GPIO_PWM2, PMW_FREQ, 100000);

        time_sleep(5) ;

        hardware_PWM(pi,GPIO_PWM1, PMW_FREQ, 0);
        hardware_PWM(pi,GPIO_PWM2, PMW_FREQ, 0);
    }

    return pi ;
}

コンパイル

gcc -Wall -pthread -o pigpio_pwm pigpio_pwm.c -lpigpiod_if2 -lrt
pigpiod_if2.h をインクルードしているため、 -lpigpiod_if2 が必要。

実行

./pigpio_pwm
で gpio 18, 19 に PWMのパルス信号が 出力される。
サンプルコードでは 最初に出力した 5秒後に Duty を変えて出力。
その 5秒後に 出力を 停止する。

その他 注意事項等

pigpio を使用する場合は、実行時に sudo は不要。
pigpiod のデーモンが必要。
通常の gpio へのアクセスは gpio_write, gpio_read を使用する。

pigpiod_if2.h


2021年9月25日土曜日

raspberry pi : apt upgrade で エラー発生 ( Fatal Python error )

現象:

apt upgrade 実行時、Fatal Python error が発生し、upgrade できない。

原因:

不明。

対処 (暫定) :

OS 再インストール

経緯:

久しぶりに apt update, apt upgrade を行ったところ、apt upgrade で以下の様なエラーが発生。

 :
 :
取得:408 http://archive.raspberrypi.org/debian buster/main armhf vlc-plugin-visualization armhf 3.0.12-0+deb10u1+rpt2 [142 kB]
取得:409 http://archive.raspberrypi.org/debian buster/main armhf cups-pk-helper armhf 0.2.6-1+rpi1 [69.0 kB]
513 MB を 3分 18秒 で取得しました (2,593 kB/s)
Fatal Python error: initimport: can't import _frozen_importlib
ValueError: bad marshal data (unknown type code)

Current thread 0xb6faaad0 (most recent call first):
Aborted
E: 子プロセス /usr/bin/apt-listchanges --apt || test $? -lt 10 がエラーコード (1) を返しました
E: Failure running script /usr/bin/apt-listchanges --apt || test $? -lt 10
$

対処として、以下を行ったが、効果なし。

  1. .pycファイルを削除 --- 効果なし
    sudo find /usr -name '*.pyc' -delete
    で *.pyc を削除して apt upgrade を実施したが、効果なし
  2. python, python3 の再インストール --- 効果なし
    ソースコード を wget して、コンパイル/インストール したが、効果なし

 また、ufw status 等でも 同様のエラーが発生。
 1カ月程古い バックアップイメージ で 復元したが、現象変わらず。
 何かのファイルが壊れているのかもしれないが、原因不明で  upgrade, install ができず、このままにしておくわけにはいかない。
修復を諦め、最新の OS バージョンで再度インストールを実施した。

raspberry pi : FTPサーバーのインストール

 目的:

FTPサーバーをインストールして Windows等 からのファイルアクセスができるようにする。

手順:

以下の手順で vsftpd をインストールする。
  1. パッケージリストの更新、パッケージのアップデートを行う。
    sudo apt update
    sudo apt upgrade

  2. vsftpd のインストールを行う。
    sudo apt install vsftpd
     
  3. raspberry pi 起動時に vsftpd も立ち上げる様にする。
    sudo systemctl enable vsftpd

  4. /etc/vsftpd.conf を修正して ファイルの書き込みを許可する。
    sudo vi /etc/vsftpd.conf

    #write_enable=YES

    write_enable がコメントアウトされているので、#を消して有効にする。

ファイル転送:

 Windows PC 等 から、FTPクライアントソフト ( WinSCP 等 ) からアクセスし、ファイル転送できる事を確認する。


 

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
  $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>

<?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 制御) ) に置き換えたものとなる。
プログラムを以下に示す。
#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)" を入力すると プログラムは停止する。

2020年12月5日土曜日

raspberry pi : C言語で LED 調光 (PWM 制御)

目的:

C言語で PWMを使用した LED調光を行う。

環境/構成:

PWM は 2系統あり、それぞれ割り当てることができる GPIO  は

  • PWM Channel 0 : GPIO12、GPIO18
  • PWM Channel 1 : GPIO13、GPIO19

である。

環境/構成は、C言語で LED ON/OFF と同様であるが、LED 接続回路 は 下図の通り

PWM に設定できる GPIO 4本にLED を接続。


PWM制御:

 wiringpi を使用して PWM制御を行うには、
  1. wiringPiSetupGpio で wiringpi の初期設定を行う。
    (Gpio でなくても良いが、ここでは Gpio番号を使用する前提とする。)
  2. pinMode で PWM_OUTPUT を指定する。
  3. pwmSetMode で PWM のモード (バランス/マーク・スペース) を指定する。
  4. pwmSetClock で 1レンジ当たりのクロック数を設定する。
  5. pwmSetRange で 1周期のレンジ数 (分解能) を設定する。
  6. pwmWrite で パルス幅('H' のレンジ数) を設定する。

を行う。

pinMode の設定:

pinMode (GPIO番号, PWM_OUTPUT)
でpinMode を設定する。
これを実行すると、PWMが初期状態 (バランスモード) に戻ると思われる。
( 設定した GPIO番号(channel) と異なるGPIO番号(channel) にも影響 )
この為、PWMの設定(モード,クロック,レンジ)は pinMode を設定した後に行う必要がある。

PWM のモード

PWM のモードには バランスモード とマーク・スペースモードがある。
マーク・スペースモード
一定周期で パルスが発生し、パルス幅を変化させる。
pwmSetMode(PWM_MODE_MS)
バランスモード
デューティーが 50% に近づくほど 周期が短くなる。
pwmSetMode(PWM_MODE_BAL)
モードの設定は、channel 0,1 共通。

パルス周期、パルス幅の設定

パルス周期、パルス幅の設定は、pwmSetClock, pwmSetRange, pwmWrite で行う。
パランスモードの場合、デューティー 0 (100%) の場合の周期が設定値になる模様。
ベースのクロックは 19.2MHz。
pwmSetClock(clock)
1レンジ当たりのクロック数を設定する。
1レンジの長さは (1/19.2MHz)*クロック数 となる。
クロック数の設定は、channel 0,1 共通。
pwmSetRange(range)
1周期のレンジ数(PWM周期の分解能) を設定する。
PWMの周期は レンジ数 * クロック数 * (1/19.2MHz) となる。
PWMの周波数は 19.2MHz/(レンジ数 * クロック数) となる。
レンジ数の設定は、channel 0,1 共通。
pwmWrite(GPIO,width)
GPIO番号とパルス幅(レンジ数)を設定する。
パルス幅(時間)は パルス幅(レンジ数) * クロック数 * (1/19.2MHz) となる。

pwmSetClock(40)
pwmSetRange(256)
pwmWrite(12,128)
の場合、
周波数 : 19.2/(40*256) = 0.001875MHz
= 1.875KHz
デューティ 50%

プログラム例:

C言語での PWM を使用した LED の 調光 の例を示す。
引数として、GPIO番号とパルス幅(レンジ数) を指定する。
1レンジ当たりのクロック数は 40, 1周期のレンジ数 は 256 固定。
尚、GPIO番号のチェックは行っていない。

#include <stdio.h>
#include <stdlib.h>
#include <wiringPi.h>

#define LED_PIN 12

int main (int argc, char *argv[])
{
  int pin_no = 0 ;
  int num = 0 ;

  if (argc == 1) {
    pin_no = LED_PIN ;
    num = 256 ;
  } else if (argc == 2) {
    pin_no = atoi(argv[1]) ;
    num = 256 ;
  } else {
    pin_no = atoi(argv[1]) ;
    num    = atoi(argv[2]) ;
  }

    printf("pin_no : %d\n",pin_no) ;
    printf("num    : %d\n",num) ;

  wiringPiSetupGpio() ;
  pinMode (pin_no, PWM_OUTPUT) ;
  pwmSetMode(PWM_MODE_MS) ;
  pwmSetClock(40) ;
  pwmSetRange(256) ;

  pwmWrite(pin_no , num) ;

  return 0 ;
}

コンパイル 及び 実行:

コンパイルは、
gcc -o led_on led_on.c -lwiringPi

実行は、
sudo ./led_on 12 128
の様に行う。(GPIO番号 12 を デューティー 50% (パルス幅 128) で点灯)

実行すると、設定した GPIO番号に接続した LED が 点灯する。
尚、GPIO 12 と 18,  13 と 19 は 同じ PWM Channel  の為、片方の LED の 明るさを変えると もう一方の LED の明るさも変わる。
例えば、
GPIO#12 を パルス幅 128 で 点灯した後、GPIO#18 を パルス幅 64 で点灯すると、GPIO#12 の LED も GPIO#18 と 同じ明るさに変わる。

本プログラムでは、実行毎に pinMode の設定から行っているため、既に点灯(調光)したGPIO があると、後から実行した時の pinMode 設定から PWM設定完了までの間、先に点灯した GPIO の設定が変わってしまう。(一瞬の為、見ていてもわからないが、、、)
通常は先に、使用するGPIOの設定を全て行ってから、pwmWrite で パルス幅の設定のみを行うべきかと思う。

また、このプログラムの実行は sudo を付けて実行する必要がある。
sudo を付けない場合、

pinMode PWM: Unable to do this when using /dev/gpiomem. Try sudo?

の様なメッセージが表示され、実行できない。
/dev/gpiomem のパーミッション は、

crw-rw---- 1 root gpio 246, 0 12月  3 04:10 /dev/gpiomem

の様になっているが、gpio に所属しているユーザでも上のメッセージが表示された。
sudo 無しで実行できるようにしたいが、どうすれば良いか 不明。



 

2020年11月29日日曜日

raspberry pi : WEB から LED ON/OFF ( php - C言語 間通信 )

 目的:

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

環境/構成:

環境/構成は、 WEB から  LED ON/OFF と同じ。 

プロセス間通信:

プロセス間通信にはいろいろな種類があるが、ここではメッセージキューを使用した通信を行い、php から Cプログラムに LED ON/OFF の指示を行う。

php から のメッセージ送信

php からメッセージを送信するには、

  1. msg_get_queue (int $key , int $permissions)
    で、指定された key でメッセージキューの作成または接続を行い、IDを取得する。
    prtmissions : 0666 (default 値) 。
  2. 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 プログラムでのメッセージ受信

  1. msgget(key_t key, int msgflg);
    で、指定された key で メッセージキューの作成または接続を行い、IDを取得する。
    msgflg : 下位9bit は permission。作成を行う場合は IPC_CREAT を指定する。
  2. 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ファイル:

以下に、phpファイル を示す。
ここでは、key に "1111" を指定する。後述の Cプログラムの key と同じにする。
"ON", "OFF" の ボタンが押下された時、led_on, led_off の文字列をメッセージ送信する。
message_type は "1111" を指定しているが、特に意味はない。
<?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) を行うが、このコードは "ブログ I2K-i2lab Online - 電脳ニッポンの囁き" のコードを使用させて頂いた。
その他説明等、コード中のコメントを参照のこと。

#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 コマンド で 確認できる )




2020年11月24日火曜日

raspberry pi : WEB から LED ON/OFF

目的:

WEB画面から raspberry pi に 接続した LED の ON/OFF を行う。

環境/構成:

WEB画面から ON/OFF を行うため、

  • WEBサーバー (apache2)
  • php

のインストールを行い、php から LED ON, LED OFF のプログラムを実行する。
LED ON, LED OFF のプログラム、LED接続回路は こちら を参照。

アプリケーションインストール:

  • WEBサーバー(apache2) のインストール
    sudo apt install apache2
    インストール完了で apache が 起動する。
    ブラウザから、http://"raspberry pi の アドレス" へアクセスすると、
    "Apache2 Debian Default Page" が表示される。
  • php のインストール
    sudo apt install php
    php -v で、php のバージョンが表示される。
    また、

    php -r "echo date('Y-m-d');" で、日付が表示される。

html ( .php) ファイルの設置:

/var/www/html の下 に html 格納用のディレクトリを作成し、以下の様な html (.php)を格納する。

<?php
if ($_GET['on'] == "ON") system('./led_on') ;
if ($_GET['off'] == "OFF") system('./led_off') ;
?>

<!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 ON/OFF</p>
      <form method='get'>
        <input type='submit' name='on' value='ON' />
        <input type='submit' name='off' value='OFF' />
      </form>
    </div>
  </body>

</html>

この php では、ON ボタン の押下で ./led_on を、OFF ボタン の押下で ./led_off を実行する。

この為、php と同じディレクトリに led_on, led_off の実行ファイルを格納する。
 ( led_on, led_off の実行ファイルは こちら を参照。)
 

php 実行ユーザのグループ設定:

led_on, led_off の 実行は root で行うか、実行ユーザが gpio グループに所属している必要がある。
php の実行ユーザ ( apach2 の実行ユーザ ) は、www-data である為、 www-data に gpio グループを追加する。

sudo usermod -aG gpio www-data

www-data に 追加されたことを確認する。

groups www-data

追加されていれば、一度 raspberry pi をリブートする。

sudo reboot
 

WEB アクセスで LED ON/OFF 実行:

ブラウザから、

http://"raspberry pi の アドレス"/"html のディレクトリ"/led_ctl.php

にアクセスする。(led_ctl.php は 上で格納した php ファイル)
以下の様な画面が表示される。


ON ボタン押下 で LED ON,
OFF ボタン押下で LED OFF 

する。




2020年11月23日月曜日

raspberry pi : C言語で LED ON/OFF

 目的:

C言語で LED ON/OFF (GPIO アクセス) を 行う。

環境/構成:

本体 : raspberry pi 3B
OS : Raspberry Pi OS Lite
ライブラリ : wiringpi
インストールは、こちら を参照

LED 接続回路 : 下図の通り

LED に接続する抵抗は、
GPIO の最大電流は 16mA 。
LEDでの電圧降下分として 2V 程度とすると
R = V/I = (3.3-2)/(16^-3) = 81.25Ω
精度,誤差 等を考慮すると、
100 Ω 以上 が必用と思われる。

ここでは余裕を見て 1KΩ を使用。
(LED の仕様 (電圧降下や明るさ具合)の
 考慮が必用。
 仕様したLEDは470Ωでも結構明るかった)


プログラム:

C言語で LED の ON (GPIO 12 へ '1' ライト), OFF (GPIO 12 へ '0' ライト) を行う。
プログラムでは、

  •  include ファイル として、<wiringPi.h> が必用。
  •  初期設定として、wiringPiSetupGpio() を実行。
  •  GPIO ピンのモード設定として pinMode (GPIO番号, OUTPUT) ; を実行。
  •  GPIOへのライトは、 digitalWrite (GPIO番号, レベル (0/1) ) ; を実行。

を行う。

wiringPiSetupGpio() は、 Broadcom の GPIOピン番号で アクセスを行う場合に使用する。
代わりに wiringPiSetup() を使用すると、wiringpi 番号 (wiringpi の ピン番号)でアクセスを行う。ここでは、GPIOピン番号でアクセスするようにする。

LED ON と LED OFF の サンプルプログラムは、以下の通り。

#include <wiringPi.h>
#define led_pin 12

int main (void)
{
  wiringPiSetupGpio() ;
  pinMode (led_pin, OUTPUT) ;

  digitalWrite (led_pin, HIGH) ;

  return 0 ;
}
#include <wiringPi.h>
#define led_pin 12

int main (void)
{
  wiringPiSetupGpio() ;
  pinMode (led_pin, OUTPUT) ;

  digitalWrite (led_pin, LOW) ;

  return 0 ;
}

コンパイル:

コンパイル時、lオプションで wiringPiを指定する。

gcc -o led_on led_on.c -lwiringPi
gcc -o led_off led_off.c -lwiringPi

これで、led_on と led_off の実行ファイルができる。

実行:

wiringPiSetupGpio() は、root 権限が必用な為、コンパイルした実行ファイルを実行する場合は、sudo を付ける必用がある。
但し、gpio グループに所属していれば、sudo を付けなくても実行可能。この為、GPIOアクセスを行うユーザは gpio グループに所属していた方が便利。
尚、pi ユーザは、gpio グループに所属している。

./led_on
で LED が 点灯
./led_off
で LED が消灯
する。



raspberry pi : wiringpi を使う

 目的:

c言語 から raspberry pi の GPIO 制御を行う為、wiringpi をインストールする
 * wiringpi は 非推奨とのこと。 pigpio を使用した方が良い。
  ( pigpio 使用例 : 
C言語で LED 調光 (pigpio を使用した PWM 制御)  )

インストール:

C言語から GPIO アクセスを行うためには wireingpi を使用するのが楽の様なので、
以下の手順でインストールする。 

cd /tmp
wget https://project-downloads.drogon.net/wiringpi-latest.deb
sudo dpkg -i wiringpi-latest.deb

尚、
sudo apt install wiringpi
でもインストールできるが、現時点(2020/11/23) ではバージョンは 2.5.0 がインストールされ、このバージョンは raspberry pi 4 には 対応していない。

 コマンドライン操作:

wiringpi をインストールすると、コマンドラインから直接 GPIO アクセス可能となる。
以下に、主なコマンドを示す。

情報表示
gpio -v : バージョン表示
gpio readall : ピンの状態を表示

ピンモード設定
gpio [-g] mode <pin> out : <pin> を 出力(out)に設定
gpio [-g] mode in : <pin> を 入力(in)に設定
* -g を付加した場合、<pin> は GPIO番号。付加しない場合は wiringpi PIN番号

IO操作
gpio [-g] write <pin> 0 : <pin> に 0 ('L') を出力
gpio [-g] write <pin> 1 : <pin> に 1 ('H') を出力
gpio [-g] read <pin> : <pin> の 値を取得

その他のコマンドは、Gordons Projects (https://projects.drogon.net/) のページの "The GPIO Utility" (https://projects.drogon.net/raspberry-pi/wiringpi/the-gpio-utility/) を参照。

wiringpi PIN番号は、以下 (gpio readall 結果例) を参照。
wPi が wiringpi PIN番号。 BCM は GPIO番号。



2020年11月14日土曜日

raspberry pi : OS インストール(SSH, 無線LAN)

目的:

ラズベリーパイ に raspios  をインストールする。
ラズベリーパイ 用には モニタ、キーボード、マウス、有線LAN は接続せず、 Windows PC から無線LANで SSH接続して行う。

手順: 

Raspberry pi の モニタ、キーボード、マウス、有線LAN は 接続しない前提での インストール手順。
LAN は 無線LAN。
今回は、raspberry pi 3B に、Lite版 をインストール。

(1) OS ダウンロード

http://www.raspberrypi.org/downloads/
からダウンロードする。
但し、上記( 公式サイト) からのダウンロードが失敗が多い。
ミラーサイトは以下。
 (なぜか、ダウンロード先がネットワークドライブだと失敗する。 
  ローカルドライブだと成功する。)

・Raspberry Pi OS with desktop and recommended software
    http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_full_armhf/images/
  デスクトップ環境 + 公式おすすめのソフトウェア
 
・Raspberry Pi OS with desktop
    http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_armhf/images/
   デスクトップ環境
 
・Raspberry Pi OS Lite
    http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_lite_armhf/images/
   デスクトップ環境 (X Window)  なし
 
今回は、"Raspberry Pi OS Lite" を使用。

(2) SDカードをフォーマット

SDカードを "SDFormatter" で 上書きフォーマット。

(3) OS を SDカードに書き込み

ダウンロードしたファイル を SD に書き込む。
書き込みには、balenaEtcher を使用した。
balenaEtcher は、.zip ファイルのまま書き込める。

(4) SSH ファイル を SDカードに書き込み

空のSSH ファイルを SDカードの boot ディレクトリに作成する。
Windows の エクスプローラで SDカードを開くと boot ディレクトリが表示される。
ここに、右クリックメニュー から 新規作成 > テキスト文書 を選択し、
ファイル名を SSH に変更する。 (拡張子は無し。中身は不要。ファイルサイズ 0 )

(5) wpa_supplicant.conf ファイルを SDカードに書き込み

以下の内容のファイルを SDカードの boot ディレクトリに作成する。
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=JP

network={
  ssid="[SSID]"
  psk="[パスフレーズ]"
  key_mgmt=WPA-PSK
  scan_ssid=1
}
[SSID], [パスフレーズ] は、各自の環境に合わせた値を設定。
"scan_ssid=1" は、SSID を非公開にしている場合に必要。

(6) Power ON

Raspberry Pi に SDカードを挿入して電源を接続し、電源onする。

(7) SSH でLOGIN

raspberry pi に SSH で LOGIN する。
IPアドレスは DHCP で割り当てられた IP アドレスで 立ち上がるため、IPアドレスは推定で指定する。
 NetEnum 等で ネットワーク上に存在する IPアドレス (ping の通ったアドレス)  を調べ、アタリをつける。
SSH 接続時の初期値は  ID : pi,  パスワード : raspberry。
SSH 接続は、Windows 上 の端末から、例えば 以下の様に 行う。

ssh pi@192.168.1.131

(7) 初期設定

raspi-config で ロケール等の 初期設定を行う。

sudo raspi-config

で、ラズベリーパイの設定を行う。
  • raspi-config の アップデート
     8 Update  を選択して Return
    で raspi-connfig 自体の アップデートを行う
  • ロケール設定
    5 Localisation Options を選択して Return。
    L1 Locale  を選択して Return。
    ja_JP.EUC-JP EUC-JP , ja_JP.UTF-8 UTF-8 で スペースキーを押下して '*' を付け、リターンキーを押下。
  • タイムゾーン設定
    5 Localisation Options を選択して Return。
    L2 Timezone  を選択して Return。
    アジア を選択してリターンキーを押下後、東京を選択してリターンキーを押下。
  • WLAN Country 設定
    5 Localisation Options を選択して Return。
    L4 WLAN Country  を選択して Return。
    JP Japan を選択してリターンキーを押下。

    Finish  を選択して Return で リブートする。

(8)ユーザ追加/パスワード設定

  1. root のパスワードを設定
    sudo passwd root
    で、root の パスワードを 設定する。
  2. 新規ユーザを設定
    通常使用するユーザを追加する。
    sudo adduser <新規ユーザ名>
    でユーザを追加する。
  3. 追加したユーザのグループを pi と同じグループにする
    pi と同じグループとする為、pi のグループを表示する。
    groups pi
    でグループが表示される。
    sudo usermod -G <pi の グループ> <新規ユーザ名>
    で、グループを追加する。
     (pi のグループは、',' 区切りで pi,adm,…… の様に 列挙する )
  4. pi ユーザのパスワードを変更する。
    piユーザのパスワードをデフォルトから変えておく。
    passwd
    で新しいパスワードを入力する。
  5. pi ユーザをリネームする。
    pi での接続を終了し、追加した新規ユーザで SSH 接続しなおす。
    ユーザ名 pi は、default のユーザ名の為、セキュリティ観点からリネームする。
    sudo usermod -l <新ユーザ名> pi

  

(9) パッケージ更新

sudo apt update
で、パッケージ管理ツールをアップデートする。
 (パッケージリストの更新)

sudo apt upgrade
で、アップグレードをする。(インストールされてるパッケージの更新)

(10) IPアドレス固定

/etc/dhcpcd.conf に以下を追記して IPアドレスを固定。
 ( /etc/dhcpcd.conf 内に 記述例があるので、それを参考に記述 )
sudo vi /etc/dhcpcd.conf
 
 

interface wlan0
static ip_address=***.***.***.***/24        // IPアドレスを指定する
static routers=***.***.***.***              // ルーターのIPアドレスを指定する
static domain_name_servers=***.***.***.***  // DNS の IPアドレスを指定する

設定後、
sudo reboot
でリブートし、設定した IPアドレスで接続できることを確認。 

(11) ホスト名変更

/etc/hostname と /etc/hosts に記載されている名前を変更し、リブートする。

sudo vi /etc/hostname
sudo vi /etc/hosts

で、それぞれ raspberrypi と書かれたところを 新しいホスト名に変更。
その後、

sudo reboot

でリブート。
この時、
sudo: ホスト raspberrypi の名前解決ができません: ホスト名にアドレスが割り当てられていません
のメッセージが発生するが、リブートする。

リブート後は、新しいホスト名となる。 

 

 

2020年8月4日火曜日

raspberry pi : NFSサーバーのインストール

目的:

NFSサーバーをインストールし 接続した USB HDD を NFS で共有できるようにする。

手順:

以下の手順で nfs-kernel-server をインストールし、共有ディレクトリの設定を行う。
  1. パッケージリストの更新、パッケージのアップデートを行う。
    sudo apt update
    sudo apt upgrade
     
    この時、カーネルの更新が行われた場合は、再起動する。
    sudo reboot
     
  2. nsf-kernel-server のインストールを行う。
    sudo apt install nfs-kernel-server
     
  3. /etc/export を編集し、共有ディレクトリを設定する。
    sudo vi /etc/exports

    以下の書式でディレクトリを追記する。
    <共有ディレクトリ> <ホスト1>(オプション) <ホスト2>(オプション) …

    例:
    /mnt/hdd1 192.168.1.0/255.255.255.0(rw,sync)

  4. 設定を反映する
    exportfs -ra

以上で、NFSサーバーのインストール、設定は終了。

クライアント側の設定については、
  Windows10の場合 はこちら
  WSL では NFS クライアント は使用できなさそう。


/etc/export 書式 :

<共有ディレクトリ> <ホスト1>(オプション) <ホスト2>(オプション) …

<共有ディレクトリ>
共有させたいディレクトリを記載
<ホスト>
共有ディレクトリにアクセスするクライアントを記載
ホスト名, IPアドレス, IPネットワーク  等を記載
IPネットワークは、
192.168.1.0/24
192.168.1.0/255.255.255.0
の様な形式。
(オプション)
主なオプションを以下に示す。
rw             : 読み出し、書き込み 可能
ro             : 読み出し専用 (default)
sync           : 同期書き込みを有効にする (default)
async          : 非同期書き込み(遅延書き込み)を有効にする
root_squash    : root としての書き込みを行わない様にする。(default)
                 (rootのuidとgidをanonymousのuidとgidに割り当てる。)
no_root_squash : root_squashを無効にする。
all_squash     : すべてのuidとgidをanonymousのuidとgidに割り当てる。
anonuid=uid    : anonymousに割り当てるuidを指定する。
anongid=gid    : anonymousに割り当てるgidを指定する。
secure         : 1023番以前のポートの接続のみ許可する。 (default)
insecure       : 1024番以降のポートの接続も許可する。


Windows10 : NFSクライアントのインストール

目的:

Windows10 に NFSクライアント をインストールし、Linux に接続した USB HDD を NFS で共有できるようにする。

手順:

以下の手順で NFSクライアント を有効化し、NFS アクセスの設定を行う。
  1. NFS クライアントの有効化
    1. スタート(画面左下) を右クリックし、「アプリと機能」を押下
    2. 右上 関連設定 の 「プログラムと機能」を押下
    3. 左側にある 「Windowsの機能の有効化または無効化」を押下
    4. 「NFS用サービス」の 「NFSクライアント」にチェックをして、「OK」を押下
       
  2. マウント
    1. スタート(画面左下) を右クリックし、「コマンドプロンプト」を押下
      (管理者権限ではない方)
    2. mount <NFSサーバ>:<exportディレクトリ> <マウントドライブ>
      で、NFSサーバーのディレクトリをマウントする。
      例:
      mount 192.168.1.91:/mnt/hdd1 w:¥

  3. アンマウント
    1. umount <マウントドライブ>
      例:
      umount w:¥

アクセス時の uid, gid:

マウント時の uid, gid を指定するには、¥Windows¥System32¥drivers¥etc ディレクトリに passwd ファイル, group ファイルを 作成する必要がある。
作成しない場合の uid, gid は 適当な値(?) になっている。
uid, gid の指定は、以下の様な ファイルを作成して行う。

uid :

¥Windows¥System32¥drivers¥etc¥passwd
に、
<Windows ユーザ名>:x:<uid>:<gid>:<コメント>::
の形式で記入する。
例: (Windows ユーザ名=hoge, uid=1001, gid=1001 の場合)
hoge:x:1001:100:hoge::

gid :

¥Windows¥System32¥drivers¥etc¥group
に、
<Windows 所属グループ名>:x:<gid>:
の形式で記入する。
例: (Windows ユーザ名=Administrators, gid=1001 の場合)
BUILTIN¥Administrators:x:1001:
( Administrators の場合は、前に BUILTIN¥ を付ける )

passwd, group ファイルを作成/保存したら、内容を反映させる為に 一度 アンマウント して、再度 マウント を行う。

以上

2020年5月10日日曜日

raspberry pi : 無線LAN設定

目的:
無線LAN(WiFi) を使用できるようにする。

概要:

手順:
  1. 無線LAN I/F の確認
    $ ifconfig
    で、wlan0 等 の 無線LAN I/F が存在することを確認。
     
  2.  SSID, パスフレーズ(PSK:事前共有キー) を設定する。
    $ sudo vi /etc/wpa_supplicant/wpa_supplicant.conf
    で、wpa_supplicant.conf に 以下の様に SSID, パスフレーズを設定する。

    ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
    update_config=1
    country=JP
    
    network={
      ssid="[SSID]"
      psk="[パスフレーズ]"
      key_mgmt=WPA-PSK
      scan_ssid=1
    }
    

    [SSID], [パスフレーズ] は、各自の環境に合わせた値を設定。
    "scan_ssid=1" は、SSID を非公開にしている場合に必要。
     
    psk を 暗号化 (256bit ハッシュ化) したい場合は、
    $ wpa_passphrase [SSID] [パスフレーズ]
    で 暗号化されたpsk値をを取得する。
    $ wpa_passphrase SSID PASSPHRASE
    network={
            ssid="SSID"
            #psk="PASSPHRASE"
            psk=38497220976092fc2707a838e4d4385019256149f99f935be22c90159d3b8373
    }
    

    取得できた psk値 を "[パスフレーズ]" の代わりに設定する。

    $ sudo reboot
    でリブートすると、DHCP により IPアドレスが設定される。
    ( ifconfig で確認する )
       
  3.  固定IP 設定
    $ sudo vi /etc/dhcpcd.conf
    で、固定IP 等を設定する。
    設定は 有線LAN と同様に設定する。
    # 有線LAN  IPアドレス設定
    interface eth0
    static ip_address=192.168.1.90/24
    #static ip6_address=fd51:42f8:caae:d92e::ff/64
    static routers=192.168.1.1
    static domain_name_servers=192.168.1.91 8.8.8.8 fd51:42f8:caae:d92e::1
    
    # 無線LAN  IPアドレス設定
    interface wlan0
    static ip_address=192.168.1.120/24
    static routers=192.168.1.1
    static domain_name_servers=192.168.1.91 8.8.8.8 fd51:42f8:caae:d92e::1
    

2020年4月17日金曜日

raspberry pi : スマホ(android) から Samba のファイルが見えない

現象:

スマホ(android)にインストールした X-Plore から Samba のファイルが見えない

対処:

X-Plore に設定した Raspberry Pi 4 への ユーザ名を削除することでファイルが見える様になった。

状況:

スマホにインストールした X-Plore から Raspberry Pi 4 に入れた Samba (V. 4.9.5) のファイルが見えない。
 ( ディレクトリは見えるが、中を見れない )
Windows10 からは 問題なくファイルにアクセス可能。

Raspberry Pi 3 の samba (V.  4.2.14) は アクセスできている。
設定は、同様の設定。(と思っている)

X-Plore の 表示では、
 Raspberry Pi 4 : SMB1
 Raspberry Pi 3 : SMBv2
となっている。

Log ( /var/log/samba/log. ) を確認したところ、 " Bad SMB2 signature for message" のメッセージがある。
また、( /var/log/samba/log.[IPアドレス] ) を確認すると、"No such user (ユーザ名) [?] - using guest account"のメッセージがある。

X-Plore に設定していた Raspberry Pi 4への ユーザ名 を消したところ、ファイルが見えるようになった。

何が悪いのか 不明。
設定が悪いのか ?,   X-Plore の 問題か ?,  samba の 問題か ?

2020年4月16日木曜日

raspberry pi : VPNサーバーのインストール

目的:
自宅外から自宅のネットワークにアクセスできるようにする。
 
概要:
VPNサーバーとして Softether をインストールし、VPN接続で 自宅外から SSH接続やネットワークドライブ(samba) へのアクセスを行えるようにする。


手順:
  1. bridge-utils のインストール
    VPN接続でVPNサーバー自身(VPNサーバーをインストールした raspberry pi) にアクセスできるようにする為、仮想ブリッジを経由して物理NICアクセスする必要がある。
    1. bridge-utils をインストールする
      $ sudo apt install bridge-utils
       
    2.  /etc/network/interfaces に設定を追加
      $ sudo vi /etc/network/interfaces
      auto br0
      iface br0 inet manual
      bridge_ports eth0      <--- ブリッジ接続するポートを設定
      bridge_maxwait 10
      
       
    3. dhcpcd.conf でIPアドレスを設定する。
      $ sudo vi /etc/dhcpcd.conf
      denyinterfaces eth0
      
      interface br0
      static ip_address=192.168.1.91/24
      static routers=192.168.1.1
      static domain_name_servers=192.168.1.1 8.8.8.8
      
      ブリッジ(br0) に IPアドレス等を設定する。
      ブリッジ接続するポート(eth0) の 設定は削除(コメントアウト) し、
      denyinterfaces で DHCP によるIPアドレスの割り当てが無いようにする。
      denyinterfaces の 設定は、ポートの設定(他ポートも含む)よりも前に記述する。
        
    4.  リブートする
      $ sudo reboot
      リブートして、ifconfig 等で設定を確認する。
       
     
  2.  SoftEther のインストール
    1. SoftEther ソフトウェアの URL 確認 (WEBブラウザで確認)
      SoftEtherダウンロードセンター ( https://www.softether-download.com/ja.aspx) にアクセスする。
       「コンポーネントを選択」で 「SoftEther VPN Server」 を選択
       「プラットフォームを選択」で 「Linux」を選択
       「CPU を選択」 で 「ARM EABI (32bit)」を選択
       最新版のダウンロードファイルのURL を取得する。
        ( 右クリック して リンクのアドレス(URL)を コピーする )
       
    2. SoftEther ソフトウェアをダウンロードし、解凍する。
      以降は root で作業を行う。
      任意のディレクトリで、
      $ su
      # wget [取得した URL]
      # tar zxvf [ダウンロードしたファイル名]
          --> vpnserver ディレクトリができる。
       
    3. Make を実行
      vpnserver ディレクトリに移動して make を実行する。
      # cd vpnserver
      # make
          --> licence agreement を読み (1を選択)、同意 (1を入力) する。
          ( Ver 4.38 では 入力の要求は無かった。 2021.09/25 )
       
    4. vpnserverディレクトリを /usr/local に移動する。
      # cd ..
      # mv vpnserver /usr/local/
       
    5. パーミッションを変更
      # cd /usr/local/vpnserver
      # chmod 600 *
      # chmod 700 vpncmd
      # chmod 700 vpnserver
       
    6. 自動起動のサービスを作成する
      # vi /etc/systemd/system/vpnserver.service
      [Unit]
      Description=SoftEther VPN Server
      After=network.target network-online.target
      
      [Service]
      User=root
      ExecStart=/usr/local/vpnserver/vpnserver start
      ExecStop=/usr/local/vpnserver/vpnserver stop
      Type=forking
      RestartSec=3s
      WorkingDirectory=/usr/local/vpnserver/
      #ExecStartPost=/bin/sleep 10 ; brctl addif br0 tap_vlan
      
      [Install]
      WantedBy=multi-user.target
      
      コメントアウトした行は、管理マネージャで tap を設定した後、コメントアウトを解除する。
        
    7. サービスを起動する
      # systemctl start vpnserver

      起動確認
      # systemctl status vpnserver.service
       
    8. 自動起動を有効にする
      # systemctl enable vpnserver.service
       
    9. リブートして、サービスを確認する
      # reboot
      $ sudo systemctl status vpnserver.service
       
  3. 管理マネージャーの設定
    1. Windows PC に管理ソフトウェアをインストールする。
      SoftEtherダウンロードセンター ( https://www.softether-download.com/ja.aspx) にアクセスする。
       「コンポーネントを選択」で
         「SoftEther VPN Server Manager for Windows」 を選択
       「プラットフォームを選択」で
         「Windows (.Zip package without installeers)」を選択
      ダウンロードしたファイルを解凍し、vpnsmgr.exe を起動する。
       
    2. SoftEther VPN Server への接続設定
      「新しい接続設定」をクリック
      「接続設定名」 に接続先の 任意の名前を設定
      「ホスト名」 に SoftEther VPN Server をインストールした raspberry pi のIPアドレスを設定
      「ポート番号」に 443 を設定
      「OK」 を押下
       
    3. SoftEtheer VPN Server へ接続
      「接続」をクリック
      管理者のパスワード設定ダイアログが開くので、パスワードを設定。
       
    4. 簡易セットアップ
      SoftRther VPN Server / Bridge 簡易セットアップ ダイアログが開くので以下を設定。
      「リモートアクセス VPN サーバー」にチェックして 「次へ」を押下
      「はい」を押下
      「仮想 HUB 名」を入力し、「OK」を押下。(Default は VPN)
      「ダイナミック DNS ホスト名の変更」に任意の名前を設定し「閉じる」を押下
      「L2TP over IPsec」 にチェックし、上で入力した仮想HUB名を選択。
       事前共有鍵(9文字以内推奨)を決めてOKをクリックする。
      「VPN Azure 無効にする」を選択して「OK」 を押下。
      「VPN 接続を受け入れるためのユーザーの作成」で、「ユーザを作成する」を押下。
      「ユーザー名」に任意の名前 を入力、
      「認証方法」にパスワード認証 を選択、
      「パスワード認証」にパスワード を設定して 「OK」を押下
       確認画面で OK を押下する。
       作成したユーザ名が表示されたら、閉じるを押下する。
      「ローカルブリッジの設定」で、raspberry pi の LAN のポート名 (eth0 等)を選択して 閉じる を押下。
       
    5. ローカルブリッジの設定
      「ローカルブリッジ設定」を押下
       上で設定した仮想HUB を選択して、「ローカルブリッジの削除」を押下
      「新しいローカルブリッジの定義」で
       「仮想HUB名」を入力。(例えば VPN)
       「作成する種類」で 「新しいtapデバイスとのブリッジ接続」を選択
       「新しいtapデバイス名」を設定。(例えば、vlan)
       「ローカルブリッジを追加」を押下。
      「閉じる」を押下
      「暗号化と通信関係の設定」を押下
      「暗号化アルゴリズム名」を「DHE-RSA-AES256-SHA」に変更して「OK」を押下
       
    6. 自動起動のサービスの修正
      $ sudo vi /etc/systemd/system/vpnserver.service 
      自動起動サービスの コメントを外す。
      ローカルブリッジの設定で 「新しいtapデバイス名」を vlan 以外に設定した場合は、”tap_vlan" を "tap_[新しいtapデバイス名]” に変更する。
    7. raspberry pi をリブートする
      管理マネージャを閉じ、raspberry pi をリブートし、tap が ブリッジされている事を確認する。
      $ sudo reboot
      $ brctl show br0
      bridge name    bridge id             STP enabled    interfaces
      br0            8000.5ea8b6f10493     no             eth0
                                                          tap_vlan
      
       
  4. ルータ設定
    ルータのポートマッピングで、500/UDP, 4500/UDP を ラズベリーパイのIPアドレスにマッピングする。
    設定方法は、各ルータのマニュアルを参照。
     
  5. ファイアウォール解放
    ラズベリーパイのファイアウォール設定で、500/UDP, 4500/UDP を通過させるように設定する。
    sudo ufw allow 500/udp
    sudo ufw allow 4500/udp
     
  6. 通信確認
    スマホ等からVPN 接続できることを確認する。
    ・android の場合の例 (4G 等で接続)
    設定 - ネットワークとインターネット - VPN
    で、右上の + をクリックし、VPNプロファイルの編集を行う。
    (機種 や android バージョンによって 異なるかも)
     名前       : 任意の名前
     タイプ     :L2TP/IPSec PSK
     サーバーアドレス:ダイナミック DNS ホスト名 に設定した名前
     IPSec事前共有鍵 :設定した 事前共有鍵
     ユーザ名    :設定した ユーザ名
     パスワード   :設定した パスワード
    等を設定して保存後、接続できる事を確認する。
    (スマホは、4G 等の異なるネットワーク で接続していること。)

    ・Windows10 の場合の例 (テザリング等で接続)
    設定 - ネットワークとインターネット - VPN
    で、 +(VPN接続を追加する) をクリックし、VPN接続を追加する。
     VPNプロバイダー    :Windows(ビルトイン)
     接続名          : 任意の名前
     サーバー名またはアドレス:ダイナミック DNS ホスト名 に設定した名前
     VPNの種類       :事前共有キーを使ったL2TP/Ipsec
     事前共有キー      :設定した 事前共有鍵
     サインイン情報の種類  :ユーザー名とパスワード
     ユーザ名        :設定した ユーザ名
     パスワード       :設定した パスワード
    等を設定し、接続できる事を確認する。
    (Windows は、テザリング等 の異なるネットワーク で接続していること。)
     
  7. LOG の所在
    VPNサーバーインストールディレクトリ下に log ディレクトリがある。
    接続できない場合等、server_log ディレクトリ内の log を確認して原因調査を行う。

    /usr/local/vpnserver/server_log/vpn_********.log

2020年1月17日金曜日

linux : サービスの作成、管理

目的:

Linux での サービスの作成、管理について記しておく。

概要:

サービスの作成、管理は systemctl で行う。
systemctl は rootで実行, または sudo をつけて実行する。
サービスは、"unit" 単位で管理される。

systemctl コマンド:


  • サービス起動
    $ sudo systemctl start [unit名]
  • サービス停止
    $ sudo systemctl stop [unit名]
  • サービス再起動
    $ sudo systemctl restart [unit名]
  • サービスリロード(再読み込み)
    $ sudo systemctl reload [unit名]
  • サービスステータス表示
    $ sudo systemctl status [unit名]
  • サービス自動起動有効
    $ sudo systemctl enable [unit名]
  • サービス自動起動無効
    $ sudo systemctl disable [unit名]
  • サービス自動起動設定確認
    $ sudo systemctl is-enabled [unit名]
  • サービス一覧
    $ sudo systemctl list-unit-files --type=service
  • 設定ファイルの再読込
    $ sudo systemctl daemon-reload

サービスの作成:

  1. サービスで実行する処理(スクリプト等)を作成する。
  2. /etc/systemd/system に unit定義ファイル (下記参照) を作成する。
  3.  sudo systemctl list-unit-files --type=service で作成したサービスが表示されることを確認する。
  4.  サービスを起動する。(systemctl start [unit名])
  5. 自動起動を設定する。(systemctl enable [unit名])

unit定義ファイル:

unit定義ファイルの例

[Unit]
# サービスの説明。内容は任意
Description=unit file sample
# このUnitより先に起動するべきUnitを設定
After=network.target
 
[Service]
# 実行するコマンドやスクリプトを記述
ExecStart=/usr/bin/test.sh
# サービス停止時の Kill する単位を設定
KillMode=process
# プロセスの起動方法を指定
Type=simple
# サービス停止時の再起動条件 (no は再起動しない)
Restart=no

[Install]
# 該当ユニットへの弱い依存関係を設定
WantedBy=multi-user.target

log 確認:


サービスの log確認は、
$ sudo journalctl -u [unit名]

で行う。
このlog は、/var/run/log/journal にバイナリ形式で保存され、再起動で消えるため、 log は直近の起動後のみが確認できる。
再起動で消えないようにする為には、 /var/log に journal ディレクトリを作成し、再起動する。

$ sudo mkdir /var/log/journal

$ sudo reboot

2019年12月31日火曜日

raspberry pi : wordpress サイトの移行

目的:

raspberry pi 3 の wordpress のサイトを raspberry pi 4 に移行する。

手順:

wordpress のインストールは済んだ状態で移行作業を開始。
  1. プラグイン 「All-in-One WP Migration」のインストール
    両方の raspberry pi の wordpress に   プラグイン 「All-in-One WP Migration」 をインストール、有効化する。
     
  2. 旧 wordpress のエクスポート
    1. 旧 wordpress (raspberry pi 3) で 管理画面の左メニューから「All-in-One WP Migration」→「エクスポート」を選択。
    2. "エクスポート先" から "ファイル" を選択。
    3. 準備終了後、"***** をダウンロード" を押下してファイルを保存する。
       
  3. rapsberry pi 4 の 最大アップロードファイルサイズを大きくする。
    1. .htaccessを有効にする。
      $ sudo vi /etc/apache2/apache2.conf
      で  <Directory /var/www/> セクションの
      AllowOverride None  を
      AllowOverride All    に変更。
       
    2. .htaccess に 最大アップロードファイルサイズの設定を行う。
      $ sudo vi /var/www/html/wordpress/.htaccess
      /var/www/html/wordpress/.htaccess に 以下を追記。
    3. php_value upload_max_filesize 128M
      php_value post_max_size 128M
      php_value memory_limit 256M
      php_value max_execution_time 300
      php_value max_input_time 300
      

  4.  apache2 を再起動する。
    $ sudo /etc/init.d/apache2 restart

     
  5. 新 wordpress にインポートする。
    新 wordpress (raspberry pi 4) で  管理画面の左メニューから「All-in-One WP Migration」→「インポート」を選択。
    最大アップロードサイズが設定通りであることを確認。
    ダウンロードしたファイルをドラッグアンドドロップすると、インポートが開始される。