DELL-inspironにWindows11をクリーンインストールする方法

 

DELL inspiron 5430にLinuxをインストールした後に、
 Windowsに戻すのにいろいろハマりましたので記録に残します。

 

■まえがき

 

Windowsに対応していないソフトが有りまして、
  Linuxでシステムを作りたかったので、
  簡単にノートパソコンを購入し、
   Windowsを消してLinuxに入れ替えて使い終わったら
  Windowsに戻す!!ということを考えておりました。
 戻すときの方法を普通にマイクロソフトのサイトからWindows11を
 ダウンロードしてインストールすればよいと思っておりました。
 
 これが甘かった。

 

■ハマった所
 
 自作PCとかだと、MicrosoftからダウンロードしたWindows11の
  インストーラーのisoをdvdに焼いて起動すれば、インストールOK
   となるんですけど。
 
 本パソコンでは
  DVDから起動して進むんだけど、インストール先のHDDの指定で
   SSDのディスクが表示されない事象が発生。
 
 ここから調べたり試したりが始まって・・・
 
 M.2のSSDだと出来ない場合がある。
  とか、
 M.2のSSDだと、SerialATAじゃ無いのでNVMEがー
  とか
 BIOSでIntel VMDに関する項目を探して確認。有効の場合は無効にするか、
  有効のままドライバーを組み込んでWindowsをインストール
   とか
 いろいろ情報があったんですけど、本パソコンにはいまいち当てはまらず。
 
 何時間か経過・・・・

 

■解決

 

 なんか翻訳がおかしくて「Linuxを再インストールする」ってなってますけど、
  Winodws11のクリーンインストールが可能です。
   もともとLinuxで出荷されたのはLinuxが入るのかもです。
 
 OS Recovery Toolを以下からダウンロードして
 https://www.dell.com/support/home/ja-jp/drivers/osiso/recoverytool/w2021
 ツールを起動するとUSBにリカバリブート用のセットアップを書き込んでくれる。
 そのUSBをパソコンにセットして、
  起動直後F12を押してUSBから起動させて、後はメニューに合わせて進んでいく。
 いちおう、システム検査後、リセットを選択。

 


 Windows11の初期化へ進んで無事Windows11に戻りました。

 途中の試行錯誤でBios設定を色々いじってたので、工場出荷状態に戻したり、
  工場出荷状態に戻らない項目は手動で戻したりいろいろしましたけど、
   結果は上記の通り

音声転送プログラム

 

■前書き


 現代において
  インターネット回線を使ってPC同士で会議とか、通話とかする事が出来ます。

今回はその初歩的部分。
  pythonを使って一方通行ですが、
   音声を送るプログラムを作ってみたので、そのプログラムとセットアップ方法を
    記録しておきます。

 

■構成

 

  マイク-PC1-(LAN)-PC2-アンプスピーカー

 

■方式
 
 PC1
   PyAudioでマイクから音声を入力。44.1Khz モノラル 16Bit
    そのままUDPで宛先を指定して送信
 
 PC2
    UDPでデータを受け取って
    PyAudioでスピーカーに音声を入力。44.1Khz モノラル 16Bit

 ※この方式の欠点
    全く圧縮していないので、ネットワーク帯域を結構使う。
      といっても、計算すると
       44100×2×8=約71Kbps 
        ぐらいですので、構内LANで単独使用なら問題ないかなーと思います。
    UDPなので、順序保証とか、データの保障が無い。
      とはいえ、こちらも多少ノイズとして聞こえるぐらいの
       影響しかないかなーと思います。
     送信側と受信側で同期を取っていないので、長時間使うと遅延したり、
      バッファーがオーバーフローする可能性あり。
     送受信の両方でエラー時に自動的に再起動するとか、対処必要になると
      思われ。

 

========================
セットアップ
========================

 

■ファイル配置

 

 /usr/local/bin/audio-transferに所定のファイルを配置していく

 

[root@localhost audio-transfer]# pwd

/usr/local/bin/audio-transfer

 

[root@localhost audio-transfer]# ls -al
合計 12
drwxr-xr-x. 2 root root   57  3月 21 09:42 .
drwxr-xr-x. 3 root root   28  3月 21 09:42 ..
-rw-r--r--. 1 root root 1241  3月 21 09:42 recv.py
-rw-r--r--. 1 root root 1526  3月 21 09:42 send.py
-rw-r--r--. 1 root root 1248  3月 21 09:42 show-audio.py
[root@localhost audio-transfer]# 

 

■python準備

 

Windowsも手順は同じ。
以下はCentOSの場合を記載しています。

 

[root@localhost audio-transfer]# python --version
Python 2.7.5

古い。せめて3系にしたいなー
って事で・・・

 

yum install -y python36
yum install -y python36-devel
pip3 install pyaudio

 

■テスト

 

python3.6 show-audio.py

これで、パソコンに入っているオーディオの入出力ポートが一覧出力される。

 

 Device 0: HDA Intel HDMI: HDMI 0 (hw:0,3), Channels: 0
 Device 1: HDA Intel HDMI: HDMI 1 (hw:0,7), Channels: 0
 Device 2: HDA Intel HDMI: HDMI 2 (hw:0,8), Channels: 0
 Device 3: HDA Intel HDMI: HDMI 3 (hw:0,9), Channels: 0
 Device 4: HDA Intel HDMI: HDMI 4 (hw:0,10), Channels: 0
 Device 5: HDA Intel PCH: ALC269VC Analog (hw:1,0), Channels: 2
 Device 6: hdmi, Channels: 0
 Device 7: pulse, Channels: 32
 Device 8: default, Channels: 32
 
しかし、このままではどれがマイクからの入力なのかわからん。
 なので、0から順番に試していって、
  5番がそれである事を突き止めて、
   input_device_index = 5 #
    に決定。

 

だけど、一瞬つながった後にエラーになる。
 その一瞬に送信側でなにか叫ぶと受信側のスピーカーから音が鳴る。
  少し成功。あと一歩です。

 

Traceback (most recent call last):
  File "send.py", line 42, in <module>
    data = stream.read(chunk)
  File "/usr/local/lib64/python3.6/site-packages/pyaudio/__init__.py", line 571, in read
    exception_on_overflow)
OSError: [Errno -9981] Input overflowed

[root@localhost audio-transfer]# 

 

バッファーが足りなくなるとダメっぽいので5倍にする。
「chunk = 50240」に変更

 

Traceback (most recent call last):
  File "send.py", line 45, in <module>
    sock.sendto(data, addr)
OSError: [Errno 90] Message too long
[root@localhost audio-transfer]# 

 

今度はUDP送信でメッセージが長いって。

 

試行錯誤・・・・

 

結局googleで探して
音声をマイクから読み込む部分に「exception_on_overflow=False」を追加。
data = stream.read(chunk, exception_on_overflow=False)

 

いちおうこれで落ち無くなった。

 

いろいろいじってると判るんだけど、
chunkを大きくすると遅延が出ることが判明。
結局chunkは元に戻して1024とする。
「chunk = 1024」

 

■解決

 

音はクリアですね。デジタル通信なんだから当たり前といえば当たり前。
 しかし、圧縮してないので、理論的に考えて普通のIP電話よりクリアですね。
帯域さえ確保できれば(といいつつも、それほど大きな帯域でもないし)
44.1Khz/16Bitですから、CD音質で音を運ぶのは現代の通信回線において余裕です

 

■起動

 

受信側PC(Windows)
 python3.6 recv.py
 ※受信側はOSのFW設定でUDPの5005を開けてください。

 

送信側PC(CentOS)
 python3.6 send.py

 

■結果のソース。

 

「送信側」

 

import pyaudio
import socket
import sys

# ネットワーク設定
UDP_IP = "192.168.10.111"  # 送信先のIPアドレス
UDP_PORT = 5005  # 送信先のポート番号
addr = (UDP_IP, UDP_PORT)

# PyAudioの設定
chunk = 1024 # 音声データのチャンクサイズ
#chunk = 10240 # 音声データのチャンクサイズ
format = pyaudio.paInt16  # 音声のフォーマット
channels = 1  # モノラル
rate = 44100  # サンプリングレート
input_device_index = 5 # 

# UDPソケットの初期化
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# PyAudioの初期化
p = pyaudio.PyAudio()

# 音声入力ストリームの開始
stream = p.open(format=format,
                channels=channels,
                rate=rate,
                input=True,
                frames_per_buffer=chunk,
                input_device_index=input_device_index)

# 音声出力ストリームの開始
#output_stream = p.open(format=format,
#                       channels=channels,
#                       rate=rate,
#                       output=True,
#                       frames_per_buffer=chunk)

print("録音を開始します。CTRL+Cで終了します。")

try:
    while True:
        data = stream.read(chunk, exception_on_overflow=False)
        #output_stream.write(data)  # スピーカーから音声出力
        sock.sendto(data, addr)  # UDPで音声データを送信
except KeyboardInterrupt:
    print("録音を終了します。")

# ストリームを閉じる
stream.stop_stream()
stream.close()
#output_stream.stop_stream()
#output_stream.close()
p.terminate()

# ソケットを閉じる
sock.close()

 

 

 

「受信側」

 

import pyaudio
import socket
import sys

# ネットワーク設定
HOST = ""  # 送信先のIPアドレス
PORT = 5005  # 送信先のポート番号

# PyAudioの設定
chunk = 102400  # 音声データのチャンクサイズ
format = pyaudio.paInt16  # 音声のフォーマット
channels = 1  # モノラル
rate = 44100  # サンプリングレート

# UDPソケットの初期化
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((HOST, PORT))

# PyAudioの初期化
p = pyaudio.PyAudio()

# 音声出力ストリームの開始
output_stream = p.open(format=format,
                       channels=channels,
                       rate=rate,
                       output=True,
                       frames_per_buffer=chunk)

print("受信を開始します。CTRL+Cで終了します。")

try:
    while True:
        data, address = sock.recvfrom(chunk*2)
        #print(f"address: {address}")
        output_stream.write(data)  # スピーカーから音声出力
except KeyboardInterrupt:
    print("受信を終了します。")

# ストリームを閉じる
output_stream.stop_stream()
output_stream.close()
p.terminate()

# ソケットを閉じる
sock.close()

 

「オーディオデバイス確認」

import pyaudio

p = pyaudio.PyAudio()

# 使用可能なオーディオデバイスのリストを表示
for i in range(p.get_device_count()):
    info = p.get_device_info_by_index(i)
    print(f"Device {i}: {info['name']}, Channels: {info['maxInputChannels']}")

# 目的のデバイスのインデックスを選択
input_device_index = 0  # 例えば、リストから選んだ入力デバイスのインデックス
output_device_index = 2  # 例えば、リストから選んだ出力デバイスのインデックス

# 音声入力ストリームの開始(特定のデバイスを使用)
stream = p.open(format=pyaudio.paInt16,
                channels=1,
                rate=44100,
                input=True,
                frames_per_buffer=1024,
                input_device_index=input_device_index)  # 入力デバイスを指定

# 音声出力ストリームの開始(特定のデバイスを使用)
output_stream = p.open(format=pyaudio.paInt16,
                       channels=1,
                       rate=44100,
                       output=True,
                       frames_per_buffer=1024,
                       output_device_index=output_device_index)  # 出力デバイスを指定
 

CentOSのSELINUXとFWをOFFにしていたので、ONにして穴開けする。

 

 CentOS7.9の記事の続き

   https://ameblo.jp/fc2miha/entry-12843730608.html

 

 

■SELINUXをONにする

 

su - root

 

vi /etc/selinux/config

ELINUX=enforcing
SELINUXTYPE=targeted

:wq

 

reboot

→SELINUXをONにすると起動が遅くなった

 

getenforce
→Enforcingになっている

 

■FWをONにして穴開け

 

systemctl enable firewalld


systemctl start firewalld


systemctl status firewalld

 

FWがONになる。この時点でasteriskはうまく動作できない

 

■FW穴開け

 

firewall-cmd --add-port=5060/udp --zone=public --permanent

 

firewall-cmd --reload

 

firewall-cmd --list-all

 

reboot

 

asteriskの設定 ガイダンスを流した後に通話開始

 

 

■音声ファイルをサーバー上に配置する。


ls /var/lib/asterisk/sounds/en
上のディレクトリにeiwadai.gsmという名前でファイルを配置。
このファイルはgsmなので、
 wavファイルに録音後、http://convertio.co/ja/m4a-gsm/
  にアクセスして変換しておく

 

■extensions.confの6003を書き換える。


exten => 6003,1,Answer()
exten => 6003,2,Playback(eiwadai)
exten => 6003,3,Dial(PJSIP/6003,,r)
exten => 6003,4,Hangup()

 

answerで電話をとって、Playbackで音声ファイルを再生する。
その後、ダイヤルする

SIPクライアントzoiperをLinuxのCentOS7.9へインストール

 

SIPクライアントzoiperをLinuxへインストールする場合に
 Netに出回っている情報と違ったのでハマりました。
 みんなハマってないのかなー

 

CentOS7.9にSIPクライアントであるZoiperをインストールする記事です。

 

■ダウンロード

 

zoiperのページからtar.xz版をダウンロード

 

■解凍

 

tar Jxfv Zoiper5_5.6.4_x86_64.tar.xz

 

■起動

 

cd Zoiper5

 

./zoiper

 

エラーになる・・・

 

■エラー対応

 

./zoiper: error while loading shared libraries: libXss.so.1: cannot open shared object file: No such file or directory

 

yum install libXScrnSaver

 

■再度起動

 

./zoiper

 

起動してきた。
動作確認。
けど、いろいろ操作できない。
ctrl+Cで終了

 

■再度再度

 

suでrootになっているせいかもしれないので
一般ユーザーで再度

 

./zoiper

 

今度は大丈夫

アカウントを登録
 6003@192.168.10.11:5060
通話できる。

 

成功!!

 

■ログイン時自動起動

 

 Tweaksの自動起動に設定しようと思ったらもう既に入っていた。
 上の./Zoiperの時に設定されるらしい。

 

■自動着信設定

 

※これは、お金払わないと出来ない

 設定→通話
  着信通話処理を有効をチェック
  自動応答 3秒で設定
  再起動後も設定を維持をチェック

 

■自動ログイン設定

 

アプリケーション→システムツール→設定

 →詳細→ユーザー

 ロック解除

 自動ログイン オン

 

asteriskでSIPサーバ構築

 

■参考図書
 https://www.aska-ltd.jp/jp/blog/151
 Kindle版Asterisk徹底入門:VoIPに関する基礎知識からAsteriskによる内線電話環境を構築
 


■OSインストール

 CentOS7.9をインストール
 インストール時の選択で以下にチェック入れる
  GUI
  開発環境

 

■root

 

su - root

 

■最新化

 

yum -y update

 

■必要なパッケージ追加

 

yum install vim epel-release gcc gcc-c++ wget make bzip2 patch subversion json-c json-c-devel unixODBC unixODBC-devel mysql-connector-odbc libtool-ltdl libtool-ltdl-devel jansson-devel libsrtp-devel openssl openssl-devel dmidecode ncurses-devel libxml2-devel newt-devel kernel-devel sqlite-devel libuuid-devel gtk2-devel binutils-devel libedit libedit-devel svn

 

■SELINUXを無効化


 とりあえず開発フェーズなので無効化して進む。
  必要な穴あけは後でで考える

 

sestatus

 

vi /etc/selinux/config
SELINUX=disabled
SELINUXTYPE=targeted
:wq

 

reboot

 

getenforce

 →disabledになっている


■Pjsipをインストール

 

cd /usr/src/

 

wget https://github.com/pjsip/pjproject/archive/2.10.tar.gz

 

tar zxvf 2.10.tar.gz

 

cd pjproject-2.10

 

./configure CFLAGS="-DNDEBUG -DPJ_HAS_IPV6=1" --prefix=/usr --libdir=/usr/lib64 --enable-shared --disable-video --disable-sound --disable-opencore-amr

 

make dep

 

make

 

make install

 

ldconfig

 

■Asterisk18をインストール

 

cd /usr/src/

 

wget http://downloads.asterisk.org/pub/telephony/asterisk/asterisk-18-current.tar.gz

 

tar xvfz asterisk-18-current.tar.gz

 

cd /usr/src/asterisk-18*/

 

contrib/scripts/install_prereq install

 

./configure --libdir=/usr/lib64 --with-jansson-bundled

 

make menuselect.makeopts

 

menuselect/menuselect --enable chan_ooh323 --enable format_mp3 --enable CORE-SOUNDS-JA-WAV --enable CORE-SOUNDS-JA-ULAW --enable CORE-SOUNDS-JA-ALAW --enable CORE-SOUNDS-JA-GSM --enable CORE-SOUNDS-JA-G729 --enable CORE-SOUNDS-JA-G722 --enable CORE-SOUNDS-JA-SLN16 --enable CORE-SOUNDS-JA-SIREN7 --enable CORE-SOUNDS-JA-SIREN14 --enable app_macro --disable BUILD_NATIVE

 

contrib/scripts/get_mp3_source.sh

 

make

 

途中エラーになる。同じエラーの場合は以下の対処で・・・
chan_iax2.c:418:64: エラー: expected ‘;’, ‘,’ or ‘)’ before ‘buf’
[root@localhost asterisk-18.21.0]# find . -name chan_iax2.c
./channels/chan_iax2.c
[root@localhost asterisk-18.21.0]# vi ./channels/chan_iax2.c
    418 /* static char *auth_method_names(int authmethods, char *restrict buf) */
    419 static char *auth_method_names(int authmethods, char *buf)
    :wq

 

make install

 

make samples

 

make config

 

ldconfig

 

■Asterisk18を有効化

 

systemctl status asterisk
systemctl enable asterisk
systemctl start asterisk

 

■停止する場合
####
# systemctl stop asterisk
#

 

■ファイアウォールも無効化
 とりあえず開発フェーズなので無効化して進む。
  必要な穴あけは後でで考える
####
#
# FW stop
#
#  systemctl stop firewalld
#  systemctl status firewalld
#  systemctl disable firewalld
#  systemctl status firewalld
#

####
#
# SE-LINUX stop
#
#  setenforce 0
#  getenforce
#


■Asteriskの設定

 

内線通話設定する
Asteriskは自動応答とか、番号入力への応答とか
 色々できるソフトなんですけど、今は内線通話さえできればOKなので、
  簡単な内線設定を考える。
 
今回の設定の内容。
 内線番号は3つ。
  6001、6002、6003が存在。
 SIPサーバーのIPアドレスは192.168.10.119

 

内線通話だけなら2つのファイルを変更すれば良い。
 /etc/asterisk配下に存在
  pjsip.conf : [endpoint]は内線番号の数だけ記述する。
          内線間で通話できれば良いので同じ記述の繰り返しになる。
          ずらっと書かなければならないのか
          省略した書き方ができるかは不明。
  
  extensions.conf : 通話開始から、動作のシーケンスを記述。
            通話開始後にメニュー音声を読み上げ後に
            番号を押させて分岐もここで記述可能。

 

vi /etc/asterisk/pjsip.conf

 

[transport-udp]
type=transport
protocol=udp
;udp,tcp,tls,ws,wss,flow
bind=0.0.0.0

[6001]
type=endpoint
transport=transport-udp
context=default
disallow=all
allow=ulaw
allow=gsm
auth=6001
aors=6001
rewrite_contact=yes

[6001]
type=auth
auth_type=userpass
password=6001
username=6001

[6001]
type=aor
max_contacts=2

[6002]
type=endpoint
transport=transport-udp
context=default
disallow=all
allow=ulaw
allow=gsm
auth=6002
aors=6002
rewrite_contact=yes

[6002]
type=auth
auth_type=userpass
password=6002
username=6002

[6002]
type=aor
max_contacts=2

[6003]
type=endpoint
transport=transport-udp
context=default
disallow=all
allow=ulaw
allow=gsm
auth=6003
aors=6003
rewrite_contact=yes

[6003]
type=auth
auth_type=userpass
password=6003
username=6003

[6003]
type=aor
max_contacts=2

 

vi /etc/asterisk/extensions.conf

 

[default]
exten => 6001,1,Dial(PJSIP/6001,,r)
exten => 6001,2,Hangup()

exten => 6002,1,Dial(PJSIP/6002,,r)
exten => 6002,2,Hangup()

exten => 6003,1,Dial(PJSIP/6003,,r)
exten => 6003,2,Hangup()

 

[default]ひとつ書いておけばOKで、
 pjsip.confに書いたcontext=defaultに対応している。

 

ex...
 exten => 内線番号,シーケンス,コマンド
 シーケンスは内線番号ごとに1から記述。途中飛ばすと止まる
 Dial()は通話してくれる。
  ()の中身は
   通話するSIP技術の種類,
   タイムアウト(秒)省略可(省略時は無限),
   オプションrはリンクバックトーン有
 Hangup()は通話完了

 

■内線電話機の設定
 
 Zoiperを使用する場合。
 Linux、MacOS、Windows、Android等対応しているみたいです。
  フリーの他にも有料版あります。
   実験で使うだけなので、課金はちょっと無理。
 
 というわけで、設定項目はどのOSでも同じです。
 

 


 設定としては
  アカウント6001@192.168.10.119:5060
  SIPアカウント
   ドメイン :192.168.10.119:5060
   ユーザ名 :6001
   パスワード:6001
 5060はサーバーのポート番号5060がデフォルトみたい。
 ドメインはサーバーのIPアドレス。
  ユーザ名とパスワードはpjsip.confファイルにtype=authで
   指定したものを指定。
 
■通話

 

 上記設定できていれば、
 相手の内線番号=上記のユーザ名を入れて通話可能になります。
 

テーブルタップのパイロットランプ修理

 

JUGEMテーマ:電子工作

 

ELPAのテーブルタップ。

 


スイッチが全体で共通なのが意外と便利で愛用しております。
アースの穴もくっついていますので、
家のコンセントのアースにしっかりくっつけて使っております。

 

ところが、パイロットランプが光らなくなってしまいまして、
 ここにLEDをくっつけてみようかなーみたいな。修理記事になります。

 

それでそれで、実験開始。

 


回路

 


この回路で落ち着きました。駄目です。下の方に最新の回路を提示しています。

 最初は10KΩの抵抗を4.7KΩで始めたのですが、
  時間が経つと抵抗があっちっちになるので、やはり無理があると思い、
  10KΩに落ち着きました。下に計算式書いときます。

 

抵抗は秋月から調達した1Wまで耐えるやつです。


 

 

 

■計算


4.7Kで計算した場合、
家庭用電源の場合、実行電圧が100Vとすると、
最大の電圧が141ボルトとなり、こういう時は最大で計算します。
まず電流を出します。(LEDの電圧降下を無視するとします)
  141V÷(4.7KΩ+4.7KΩ)=15mAとなります。
 続けて抵抗ひとつにかかる電圧は最大70.5Vなりますので、
  (LEDの電圧降下を無視するとします)
 ワット数が
  70.5V×15mA=1.058W
  あっ、1W超えてますね。
   これでは危ないですね。将来焼け切れるかもですね。

    それで熱くなっておりました。

 

はい。
 10KΩで再計算します。
  141V÷(10KΩ+10KΩ)=7mAとなります。
 ワット数が
  70.5V×7mA=0.49W
  定格の半分ですね。
  これなら大丈夫でしょう。
  家庭用電源100V専用です。200Vの場合はもうちょい抵抗値上げましょう。

 


 

ある日LEDが点灯していない事に気づき、もう少し改造しました。

 

 

 

抵抗を追加 と 定電流ダイオード追加してます。

ESP32回路のノイズ対策

JUGEMテーマ:電子工作

 

いつも使っているのと同じ回路でマイコンが停止するという事象が

発生しておりましたので、事象の再現試験とその対策を実施しました。

 

■再現試験の方法。

 

旧式(なのか?まだまだ現役の部分もありますけど、)
 の『蛍光灯』を使います。
  直管40W蛍光灯+グローランプでスイッチON/OFFします。
   普通にラジオでノイズ音が「ぶちぶちっぶちー」って聞こえるぐらいノイズが発生しています。
   電源を入れるとチカチカーってグローが光って、その後に蛍光灯本体が光ります。

 

 

 

これを使えば、保護なしのESP32ぐらいは5分ぐらいで止めれます。
秋月のESP32のDevkitCだと、これぐらいでは止まらないですね。

 

■ノイズ発生の自動化

 

事象が発生するまで、スイッチを10秒ごとにON/OFFしていたのですが、
 30分もやってると、さすがに飽きてきましたので、
  マイコンのLチカと、リレーを組み合わせて自動化しました。

 

接続概要は
 ESP32--リレー--蛍光灯
  です。

 

Lチカは以下プログラムです。
 ledはパイロットランプ用です。
 led2をリレーに接続しています。
 7秒ON、3秒OFFです。全体で10秒で繰り返しますので、
 1時間で360on/offです。
  エンジンでいうと6rpmですね。

 

■ノイズ自動化のプログラム


from machine import Pin
import utime

led = Pin(13, Pin.OUT)
led2 = Pin(12, Pin.OUT)

while True:
  
  led.value(1)
  led2.value(1)
  
  utime.sleep(7)
  
  led.value(0)
  led2.value(0)
  
  utime.sleep(3)
  

■ノイズ自動化の動作

 

https://youtu.be/l3bgIuqiNKA

 

■ノイズ自動化の回路図

 

 

■試行錯誤

 

電源ラインとかにノイズが乗って停止しているのかなーと思いましたので、
 まずはコンデンサーをどんどん追加。
  470μF、1000μF、2200μFと追加していき、
   まずまずの安定感を見ていたのですが、
  完全とは言えなく、ごくまれに死にます。


 ノイズの対策としては、金属で周りを囲むとかも考えられるんですが、
 ESPの場合はWIFIの電波送受信しなきゃなので、金属で囲むのはダメっすよねー。

 ちなみに使っていた電源はスイッチサイエンスさんのUSB-UART変換のやつです。

 


これのVCCとGNDをブレッドボード用のケーブルで接続していました。
 いかにもラインからノイズ入りそうですよね。

 

それでー
 上にも書いた通り、ESP32のDEV-KITでは死なないですので、
  それを真似することにしてみました。

 

なんと、死ぬ事象はぴたりと止まりました。
 3時間経過=延べ1080蛍光灯電源ON/OFFでも停止せず。
  という結果を記録しましたので、これで大丈夫だろうという事で、
   記録に残します。

 

■回路図

 

 

追加したのは緑枠線の中。
3端子レギュレーターで5Vから降圧して、
 その後ろの3.3Vラインに0.1μFと22μFを接続しました。
  それと、効果あるかは不明ですが、ENとGND間に0.1μFを入れました。


ポイントは最短距離で結ぶ事です。

 

元々の回路でも3端子レギュレーターで3.3Vを生成してESP32に入れていたのですが、
 (スイッチサイエンスさんのシリアルUSB変換基盤にのっているやつです)

 大きく違うのは、3.3Vを生成後、最短距離で、
  ESP32の電源ラインに入れている部分ですね。
ここが長い事によって、ノイズを拾ってしまっていたんですね。
 前の回路ですと、20センチぐらいの細いケーブルを使っていましたので、そのせいですね。

 

■全体考察

 

やっぱ、電子回路、難しいですね。
 ブレッドボード上でうまくいっても現場がノイズだらけだと、
  謎の停止の事象が・・・のような事、経験してきました。
  
追加で実験したんですが、
 3端子レギュレーターではなく、DC-DCコンバーターでも
 問題なく動作しております。秋月のHT7733A仕様のやつですね。
  こちらもノイズ発生装置で1080ノイズに耐えております。

FONTX2形式をESP32のmicropythonで扱う

JUGEMテーマ:電子工作

 

前の記事

 https://ameblo.jp/fc2miha/entry-12837059330.html
 http://miha.jugem.cc/?eid=366
 
前の記事でarduinoで日本語表示の準備を書いてましたが、
フォントファイルを扱うという前提で考えた場合、
 esp32のマイクロパイソンであれば、ファイルシステムが使えるので、
 ファイルの転送も楽ですし、まずは、ESP32のmicropythonでフォントファイルを
 使えた方が良いので、そちらから進めることにします。
 
前回の記事をpythonで書き換えた感じになります。

 

■フォントファイルの準備

以下のファイル名でFONTをESPのファイル領域に入れておくこと

 

 ILGZ32XF.FNT  SJIS
 ILGZ16XF.FNT  SJIS
 ILGH32XF.FNT  ANSI
 ILGH16XB.FNT  ANSI

 

フォントの入れかたは

 ampy -p com4 -d 1 put ILGZ32XF.FNT

  とか、com4の所とファイル名の所は書き換えてください。

 

■実行結果

 

 

■プログラム

 

 https://drive.google.com/file/d/1xYPl0iTGT3D7YbjvGF4faPrTCdUnjJCk/view?usp=sharing

 

以下は抜粋

 

・ファイルを読み込んでフォントのパラメータを変数に確保

 

 f = open(FONT_FILE, 'rb')
 f_sig     = f.read(6)  #FONTX2と入る
 f_name    = f.read(8)  #フォント名
 f_width   = f.read(1)  #フォント幅 ドット
 f_height  = f.read(1)  #フォント高 ドット
 f_code    = f.read(1)  #文字コード 1=SJIS
  f_block_num = f.read(1)  #ブロック数

 

・バイナリのままだと扱いづらいのでintに変換

 パイソンはここらへんがメンドクサイ。


 width = int.from_bytes(f_width, 'little')
 height  = int.from_bytes(f_height, 'little')

 

・フォントファイルがSJISの場合はテーブル作成

 

    block_num = int.from_bytes(f_block_num, 'little')
    
    for i in range(block_num):
        f_start = f.read(2)
        bs = f_start[1] * 256 + f_start[0]
        #
        f_end  = f.read(2)
        be = f_end[1] * 256 + f_end[0]
        #
        block_start.append(bs);
        block_end.append(be);
    
    for i in range(block_num):
        print(hex(block_start[i])+"-"+hex(block_end[i]))

 

・フォントファイル中のフォントの位置を特定


    char_count = 0
    exist_flag = 0
    for i in range(block_num):
        if block_start[i] <= code and code <= block_end[i] :
            char_count = char_count + (code - block_start[i])
            exist_flag = 1
            break
        else :
            char_count = char_count + (block_end[i] - block_start[i]) + 1;
    font_size = int((width + 7) / 8) * height
    seek_point = 18 + 4 * block_num + char_count * font_size
    print(font_size)
    print(seek_point)

 

・再オープンしてseekし1フォント読み込み
 f = open(FONT_FILE, 'rb')
 f.seek(seek_point)
 font_buf = f.read(font_size)
 f.close()

 

・フォントのビット列を判定して表示
 str = ""
 for i in range(font_size):
     bit = font_buf[i];
     for b in range(8) :
         if bit & 128:
             str = str + "■"
         else :
             str = str + " "
         bit = bit << 1;
     if ((i+1) % int((width + 7) / 8) == 0) :
         print(str)
         str = ""

arduinoで日本語表示の準備

 

マイコンで表示可能な320×240ドットとかの
グラフィックディスプレーに日本語を表示しようとすると、
メモリ容量などの問題から別のメモリ(ROM)等に
漢字のデータを用意する必要があります。

 

それの為に準備されたと思われる商品がGT20L16J1Yなんですけど、
もうすでに品切れで、作っていない様子です。

 

 

 

もっと早く試していればよかったんですけど、
遅きに失した状況です。

 

■GT20L16J1Yの説明を先にすると、


 縦16ドット、横16ドット(半角は横8ドット)で文字が表現されており、
 記号、英数字、カタカナ、第一水準、第二水準の漢字が格納されている。
 点の濃淡はなく、黒を1、白を0としてデジタルデータで格納されており、
 ROMのアドレスにSPI通信でアクセスする事で1バイト毎のデジタルデータとして
 取得することが可能です。取得した1バイトのデータをさらに分解して
 1ドット=1ビットのデータとして扱うことがが可能です。
 縦16ドット、横16ドットの1文字は256ビット=32バイトで表現されています。

 

手に入らないものはしょうがないので、
他に使えそうなものがないかなと考え、思いついたのが、
昔DOS/Vで使われていたフォント形式。拡張子FNTとかだったと思う。

 

その筋で辿って行った所、いろいろと有用な情報が見つかりました。

 

以下調べた色々メモ。

 

■現在の主流は「つるータイプふぉんと」=TrueTypeFontである。


 これはWindowsとかで使われていて拡大してもギザギザにならない方式です。
 拡張子はTTFで、座標でデータを持っている。座標間を曲線で結ぶとか、
 直線で結ぶとかの情報を持っていて、大きくした場合でも
 座標に掛け算するだけなので簡単にギザギザのない文字表現が可能です。
 ただし、ロジックが難しそうなので、マイコンに向いているかと言われると、
 現時点では難しそう。
 
■FONTX2形式


 DOS/Vなどで使われていたフォント=FONTX2
 http://elm-chan.org/docs/dosv/fontx.html
 「FONTXファイルの使いかた」さんのサイトです。
 
 これによるとファイルの先頭から
 char sig[6];          //FONTX2と入る
 char name[8];         //フォント名
 unsigned char width;  //フォント幅 ドット
 unsigned char height; //フォント高 ドット
 unsigned char code;   //文字コード 1=SJIS
 unsigned char block_num; //コードブロック数
 {  // コードブロック数分続く
  unsigned short block_start; //ブロックごとのコードの開始 リトルエンディアン
  unsigned short block_end;   //ブロックごとのコードの終了 リトルエンディアン
 }
 unsigned char font_image[xx];  //フォントイメージ (※2:フォントサイズ×各ブロックのコード数の総和)
 
 半角の場合
 char sig[6];          //FONTX2と入る
 char name[8];         //フォント名
 unsigned char width;  //フォント幅 ドット
 unsigned char height; //フォント高 ドット
 unsigned char code;   //文字コード 0=ANK
 unsigned char font_image[xx];  //フォントイメージ (フォントサイズ×256)
 
 ※フォントイメージは1バイト単位で格納されるため、幅が8の倍数でない場合は後ろに0が格納される
  
■IPAフォント


 https://moji.or.jp/ipafont/ipaex00401/
 IPAフォントライセンスなるものがあり、
 上記参照ですが、3条の制限をよく読んでもらうとわかりますが、
 若干の条件はありつつも、自由に使用可能です。

 

■IPAフォントをビットマップフォントに変換


 http://ayati.cocolog-nifty.com/blog/2012/08/ipalx322416-64a.html
 「こばこのひみつ」さんのサイトです。
 ビットマップ変換済みのファイルをダウンロード可能です。
 上記IPAのフォントをWFONTXにより変換し、FUTOME.EXEでボールド加工したもの
 と解説されています。
  ILFONT03.zip
 上記のIPAライセンスに従って配布されているものですね。

 

■WFONTX


 https://www.vector.co.jp/soft/dos/writing/se002881.html
 Windows3.1用のソフトとの事で、Windows11で動かそうとしても動きませんね。
 ソースが付いてくるので、そのうち挑戦かな?と思いますけど。

 

■FUTOME.EXE
 捜索中

 

■今回の実行例

 

薔薇の ら ですね。32×32のビットマップイメージです。

 

 

■プログラム

 

全体はこちら。

 →https://drive.google.com/file/d/1J5ESzDM_8dY5jtJ8GjAUxGUL_rQacaFQ/view?usp=sharing

 

抜粋と解説です。

 

■フォントは上記で紹介した こばこのひみつさんのものです。

#define FONT_FILE _T("ILGZ32XF.FNT")

 

■structで下記のように定義しました。

 

#pragma pack (1)

struct S_FONT {
    char sig[6];          //FONTX2と入る
    char name[8];         //フォント名
    unsigned char width;  //フォント幅 ドット
    unsigned char height; //フォント高 ドット
    unsigned char code;   //文字コード 1=SJIS
} s_font;

 

struct S_BLOCK {
    unsigned short block_start; //ブロックごとのコードの開始 リトルエンディアン
    unsigned short block_end;   //ブロックごとのコードの終了 リトルエンディアン
};

 

struct S_FONT2 {
    unsigned char block_num;       //コードブロック数
    struct S_BLOCK* block; //コードブロック
} s_font2;


#pragma pack (8)


■次の関数でコードブロックまでの情報をメモリ上に展開しておきます。

 

void CFileReadDlg::OnBnClickedButton1()
{
    CFile f;

    BOOL bRet;
    CFileException ex;

    bRet = f.Open(FONT_FILE, CFile::modeRead, &ex);
    if (bRet) {
        TRACE("open success¥n");

        char buf[256];

        UINT n = f.Read(&s_font, sizeof(struct S_FONT));
        if (n == sizeof(struct S_FONT)) {
            memset(buf, '¥0', sizeof(buf));
            memcpy(buf, s_font.sig, 6);
            TRACE("%s¥n", buf);
            memset(buf, '¥0', sizeof(buf));
            memcpy(buf, s_font.name, 8);
            TRACE("%s¥n", buf);
            TRACE("width=%d¥n", s_font.width);
            TRACE("height=%d¥n", s_font.height);
            TRACE("code=%d¥n", s_font.code);
        }

        if (s_font.code == 0) { //ANSI
            s_font2.block_num = 0;
        }

        if (s_font.code == 1){ //SJIS
            n = f.Read(&s_font2.block_num, sizeof(s_font2.block_num));
            if (n == sizeof(s_font2.block_num)) {
                TRACE("block_num=%d¥n", s_font2.block_num);
            }
            if (s_font2.block) {
                free(s_font2.block);
            }
            s_font2.block = (struct S_BLOCK *)malloc(sizeof(struct S_BLOCK) * s_font2.block_num);
            n = f.Read(s_font2.block, sizeof(struct S_BLOCK) * s_font2.block_num);
            if (n == sizeof(struct S_BLOCK) * s_font2.block_num) {
                for (int i = 0; i < s_font2.block_num; i++) {
                    TRACE("block_read %x-%x¥n", s_font2.block[i].block_start, s_font2.block[i].block_end);
                }
            }

        }

    }
    else {
        TRACE("open error¥n");
        return;
    }
    f.Close();
}

 

■次の関数にsjisコードを渡すと、デバッグとしてビットマップイメージを「■」と「・」で表示します。


 「■」の所がビット1の所で、「・」の所がビット0の所です。
 1文字のみ対応です。

 この関数を呼び出す前に上の関数を呼び出しておく必要があります。

 

void ConvertDisplay(unsigned int code)
{
    int char_count = 0;
    int exist_flag = 0;


    for (int i = 0; i < s_font2.block_num; i++) {
        if (s_font2.block[i].block_start <= code && code <= s_font2.block[i].block_end) {
            char_count = char_count + (code - s_font2.block[i].block_start);
            exist_flag = 1;
            break;
        }
        else {
            char_count = char_count + (s_font2.block[i].block_end - s_font2.block[i].block_start) + 1;
        }
    }

    if (s_font.code == 1 && exist_flag == 0) {
        TRACE("見つかりません");
        return;
    }

    if (s_font.code == 0 && code>=256) {
        TRACE("見つかりません");
        return;
    }

    unsigned int font_size;
    font_size = (s_font.width + 7) / 8 * s_font.height;

    unsigned int seek_point;
    if (s_font.code == 1) {
        seek_point = 18 + 4 * s_font2.block_num + char_count * font_size;
    }
    else {  //ANSI
        seek_point = 17 + code * font_size;
    }

    CFile f;
    BOOL bRet;
    CFileException ex;

    bRet = f.Open(FONT_FILE, CFile::modeRead, &ex);
    if (bRet) {
        TRACE("open success¥n");

        unsigned char* font_buf;
        font_buf = (unsigned char*)malloc(font_size);

        f.Seek(seek_point, CFile::begin);
        unsigned int n = f.Read(font_buf, font_size);
        if (n == font_size) {
            char str[256];
            memset(str, NULL, sizeof(str));
            for (unsigned int i = 0; i < font_size; i++) {
                //TRACE("%x", font_buf[i]);
                unsigned int bit = font_buf[i];
                for (int b = 0; b < 8; b++) {
                    if (bit & 128) {
                        strcat_s(str, sizeof(str), "■");
                    }
                    else {
                        strcat_s(str, sizeof(str), "・");
                    }
                    bit = bit << 1;
                }
                if ((i+1) % ((s_font.width + 7) / 8) == 0) {
                    TRACE("%s¥n", str);
                    memset(str, NULL, sizeof(str));
                }


            }
        }
        free(font_buf);
    }
    else {
        TRACE("open error¥n");
        return;
    }
    f.Close();
}